Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Oracle存储过程和自定义函数-imooc

Oracle存储过程和自定义函数-imooc

作者头像
chenchenchen
发布于 2023-01-30 09:19:27
发布于 2023-01-30 09:19:27
68400
代码可运行
举报
文章被收录于专栏:chenchenchenchenchenchen
运行总次数:0
代码可运行

1-1存储过程和存储函数


存储在数据库中供所有用户程序调用的子程序叫做存储过程存储函数

区别:是否可以通过return返回函数值。存储函数可以通过return返回函数值,而存储过程不可以。  相同点:完成特定功能的程序。

由于通过out参数,存储过程也可以返回函数值,所以存储过程和存储函数已经没有太大的区别了。而存储函数仍然存在,是由于oracle不断升级,需要实现向下兼容,所以存储函数就一直存留着。

2-1存储过程


创建和使用存储过程

create procedure命令建立存储过程和存储函数。

语法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
create [or replace] procedure 过程名(参数列表)
as
PLSQL子程序体;

注意事项:

  • 存储过程或者存储函数,只能创建或者替换;
  • 参数可以带也可以不带;
  • as相当于PLSQL语句中的declare,用来声明变量,游标等,但是不可以省略。

2-2不带参数的存储过程:不用带括号

程序窗口中执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
--第一个存储过程:打印HelloWorld
/*
调用存储过程的两种方式:
1、exec sayHelloWorld();
2、begin
       sayHelloWorld();
       sayHelloWorld();
   end;
   /
*/
create or replace procedure sayHelloWorld
as
--说明部分
begin
   dbms_output.put_line('HelloWorld');
end;

在PL/SQL Developer中执行存储过程,命令窗口中执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
--在命令窗口显示(即打印出来)
SQL> set serveroutput on

--第一种调用方式
SQL> exec sayHelloWorld()
HelloWorld
PL/SQL procedure successfully completed

--第二种调用方式
SQL> begin
  2      sayHelloWorld();
  3      sayHelloWorld();
  4  end;
  5  /
HelloWorld
HelloWorld
PL/SQL procedure successfully completed

2-3带参数的存储过程

使用的表和数据。命令窗口中执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
create table EMP
(
  empno VARCHAR2(16) not null,
  ename VARCHAR2(16) not null,
  sal   NUMBER,
  comm  NUMBER,
  job   VARCHAR2(16),
  deptno NUMBER
);

insert into EMP (empno, ename, sal, comm, job, deptno) values ('7839', 'xiaoming', 1200, 500,  'Actor', 12);
insert into EMP (empno, ename, sal, job, deptno) values ('7566', 'xiaowang', 800, 'Lawyer', 12);
commit;

创建存储过程。程序窗口中执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
--创建一个带参数的存储过程:
--给指定的员工涨100块钱的工资,并且打印涨前和涨后的薪水
create or replace procedure queryempinform(pempno in emp.empno%type)
as
  --定义变量
  --pename这个引用变量是引用了表emp中的ename字段的类型。
  --如果emp表中ename的类型变了,pename这个字段的类型也会跟着变化
  --引用型变量可以不用知道该表中类型是什么,定义的变量跟着引用表中字段类型改变,易于维护。
  pename emp.ename%type;
  beforesal emp.sal%type;
  aftersal emp.sal%type;
begin
  --得到员工涨前的薪水
  select ename,sal into pename,beforesal from emp where empno=pempno;
  --给该员工涨100
  aftersal:=beforesal+100;
  update emp set sal=aftersal where empno=pempno; 

  --需不需要commit?
  --注意:一般不在存储过程或者存储函数中,commit和rollback

  --打印
  dbms_output.put_line('姓名: '||pename||' 涨前工资:'||beforesal||'涨后工资:'||aftersal);
end;

执行存储过程。命令窗口中执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SQL> set serveroutput on
SQL> 
SQL> begin
  2      queryempinform(7839);
  3      queryempinform(7566);
  4  end;
  5  /

姓名: xiaoming 涨前工资:1200 涨后工资:1300
姓名: xiaowang 涨前工资:800 涨后工资:900

PL/SQL procedure successfully completed

注意:

  • 要说明,参数是输入参数(in)还是输出参数(out);
  • 为保证调用多个存储过程中处在同一个事务中,所以一般不在存储过程或者存储函数中,commit或rollback;

如何调试存储过程

  • 调试存储过程最好放到Oracle数据库所在的系统或虚拟机上,解压SQL developer ,双击运行。
  • 为了确保存储过程或函数是可调试的,右键“以编译并进行调试”,点击红色按钮“调试”
  • 利用已写好的调用函数进行调试。
  • 给调试账户授权
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
grant DEBUG CONNECT SESSION ,DEBUG ANY PROCEDURE to scott;

3-1存储函数


存储函数

  • 函数(Function)为一命名的存储程序,可带参数,并返回一计算值;
  • 函数和过程的结构类似,但必须有一个return子句,用于返回函数值。

创建存储函数的语法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
create [or replace] function 函数名(参数列表)
return 函数值类型
as
PLSQL子程序体;

注意事项:

  • 与存储过程注意事项类似,不同的是,必须有个返回值;
  • 参数列表可以有,也可以没有.当没有时,函数名后面不要带括号。

例子:查询某个员工的年收入。程序窗口中执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
--存储函数:查询某个员工的年收入
create or replace function queryempannal(pempno in number)
return number
as
  --定义变量保存员工的薪水和奖金
  psal emp.sal%type;
  pcomm emp.comm%type;
begin
  --得到该员工的月薪和奖金
  select sal,comm into psal,pcomm from emp where empno=pempno;
  --直接返回年收入
  return psal*12+nvl(pcomm,0);
end;

执行存储函数得到以下结果。命令窗口中执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SQL> variable a varchar2(20)
SQL> begin
  2  :a:=queryempannal(7839);
  3  end;
  4  /
PL/SQL procedure successfully completed
a
---------
16100

4-1in和out参数


概述

  • 一般来讲,存储过程和存储函数的区别在于存储函数可以有一个返回值,而存储过程没有返回值;
  • 过程和函数都可以通过out指定一个或多个输出参数。我们可以利用out参数,在过程和函数中实现返回多个值; 
    • 存储过程和存储函数都可以有out参数;
    • 存储过程和存储函数都可以有多个out参数;
    • 存储过程可以通过out参数来实现返回值。
  • 什么时候用存储过程/存储函数? 
    • 原则:如果只有一个返回值,用存储函数;否则,就用存储过程。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
--out参数:查询某个员工姓名、月薪和职位
/*
思考:
1、查询某个员工的所有信息---->out参数太多?
2、查询某个部门中所有员工的所有信息----->out中返回集合?
*/
create or replace procedure queryempinform(eno in number,
                                           pename out varchar2,
                                           psal out number,
                                           pjob out varchar2 )
as
begin
  --得到该员工的姓名、月薪和职位
  select ename,sal,job into pename,psal,pjob from emp where empno=eno;
end;

5-1在应用程序中访问存储过程和存储函数


先看一下数据库工具类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package oracle.utils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBCUtils {
    private static String driver = "oracle.jdbc.OracleDriver";
	private static String url = "jdbc:oracle:thin:@10.1.124.134:1521:orcl";
	private static String user = "system";
	private static String password = "123456";

    // 注册数据库的驱动
    static {
        try {
			//使用Java反射机制注册
			Class.forName(driver);
			//DriverManager.registerDriver(driver);
		} catch (ClassNotFoundException e) {
			throw new ExceptionInInitializerError(e);
		}
    }

    // 获取数据库连接
    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    // 释放数据库资源
    public static void release(Connection conn, Statement sta, ResultSet rst) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                conn = null;
            }
        }
        if (sta != null) {
            try {
                sta.close();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                sta = null;
            }
        }
        if (rst != null) {
            try {
                rst.close();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                rst = null;
            }
        }
    }
}

访问存储过程

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package demo.oracle;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;

import org.junit.Test;

import oracle.jdbc.OracleTypes;
import test.oracle.utils.JDBCUtils;

public class TestProcedure {
    /*
    create or replace procedure queryempinform(eno in number,
                                        pename out varchar2,
                                        psal out number,
                                        pjob out varchar2 )
         as
         begin
           select ename,sal ,job into pename, psal,pjob from emp where empno=eno ;
         end;
         /
    */
    @Test
    public void testProcedure() {
        /*
         * {call <procedure-name>[(<arg1>,<arg2>, ...)]}
         */
        String sql = "{call queryempinform(?,?,?,?)}";
        Connection conn = null;
        CallableStatement sta = null;
        try {
            // 获取连接
            conn = JDBCUtils.getConnection();
            // 通过连接创建statement
            sta = conn.prepareCall(sql);

            // 对于in参数,赋值
            sta.setInt(1, 7839);
            // 对于out参数,申明
            sta.registerOutParameter(2, OracleTypes.VARCHAR);
            sta.registerOutParameter(3, OracleTypes.NUMBER);
            sta.registerOutParameter(4, OracleTypes.VARCHAR);

            // 执行调用
            sta.execute();

            // 取出结果
            String name = sta.getString(2);
            double sal = sta.getDouble(3);
            String job = sta.getString(4);
            System.out.println(name + "\t" + sal + "\t" + job);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(conn, sta, null);
        }
    }
}

访问存储函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package demo.oracle;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;

import org.junit.Test;

import oracle.jdbc.OracleTypes;
import test.oracle.utils.JDBCUtils;

public class TestFunction {
    /*
    create or replace function queryempannal(pempno in number)
         return number
         as
           psal emp.sal%type;
           pcomm emp.comm%type;
         begin
           select sal,comm into psal, pcomm from emp where empno=pempno ;
           return psal*12+nvl (pcomm,0);
         end;
    */
    @Test
    public void testFunction() {
        // {?= call <procedure-name>[(<arg1>,<arg2>, ...)]}
        String sql = "{?= call queryempannal(?)}";
        Connection conn = null;
        CallableStatement call = null;
        try {
            // 获取数据库连接
            conn = JDBCUtils.getConnection();
            // 通过连接获取statement对象
            call = conn.prepareCall(sql);

            // 对于out参数 声明
            call.registerOutParameter(1, OracleTypes.NUMBER);
            // 对于in参数 赋值
            call.setInt(2, 7839);

            // 执行调用
            call.execute();
            double income = call.getDouble(1);
            System.out.println("该员工的年收入为:" + income);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            JDBCUtils.release(conn, call, null);
        }
    }
}

6-1在out参数中使用光标


申明包结构 , 包头 ,包体。

案例:查询某个部门中所有员工的所有信息。

包头(申明):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
create or replace package mypackage01 as
     --使用type关键字,自定义一个光标类型
     type empcursor is ref cursor;
     procedure queryEmpList(dno in number,empList out empcursor);
end mypackage01;

包体(实现):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
create or replace package body mypackage01 as
     procedure queryEmpList(dno in number,empList out empcursor) as
     begin
          --打开光标
          open empList for select * from emp where deptno=dno;
     end queryEmpList;
end mypackage01;

在控制台,可以使用desc查看程序包的结构

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SQL> desc mypackage01
Element      Type      
------------ --------- 
EMPCURSOR    TYPE      
QUERYEMPLIST PROCEDURE 

在应用中访问包中的存储过程

注意:需要带上包名。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package demo.oracle;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;

import org.junit.Test;

import demo.utils.JDBCUtils;
import oracle.jdbc.OracleCallableStatement;
import oracle.jdbc.internal.OracleTypes;

public class TestCursor {
/*
 * --使用光标创建包头:查询某个部门下的所有员工的所有信息
create or replace package mypackage01 as
     --使用type关键字,自定义一个光标类型
     type empcursor is ref cursor;
     procedure queryEmpList(dno in number,empList out empcursor);
end mypackage01;
*/
	@Test
	public void testCursor(){
        //{call <procedure-name>[(<arg1>,<arg2>, ...)]}
		String sql = "{call mypackage01.queryEmpList(?,?)}";
		Connection conn = null;
		CallableStatement sta = null;
		ResultSet rs = null;
		try {
			conn = JDBCUtils.getConnection();
			sta = conn.prepareCall(sql);
			
			sta.setInt(1, 20);
			sta.registerOutParameter(2, OracleTypes.CURSOR);
			
			sta.execute();
			//取出该部门所有员工信息(强制转换成oracle类型)
			rs = ((OracleCallableStatement)sta).getCursor(2);
			System.out.println("员工号"+"\t"+"姓名"+"\t"+"薪水"+"\t"+"职位");
			while(rs.next()){
				int empno = rs.getInt("empno");
				String name = rs.getString("ename");
				double salary = rs.getDouble("sal");
				String job = rs.getString("job");
				System.out.println(empno+"\t"+name+"\t"+salary+"\t"+job);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			JDBCUtils.release(conn, sta, null);
		}
	}

}

Reference:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-04-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
快速学习Oracle-存储函数
一般来讲,过程和函数的区别在于函数可以有一个返回值;而过程没有返回值。但过程和函数都可以通过 out 指定一个或多个输出参数。我们可以利用 out 参数,在过程和函数中实现返回多个值。
cwl_java
2019/12/19
3560
【MySQL】MySQL的存储过程(1)
MySQL 5.0 版本开始支持存储过程。 简单的说,存储过程就是一组SQL语句集,功能强大,可以
陶然同学
2023/02/24
1.8K0
JAVA调用Oracle存储过程和函数
连接数据库的工具类: import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class JDBCUtils { private static String driver = "oracle.jdbc.OracleDriver"; private
HUC思梦
2020/09/03
1.6K0
Oracle应用实战八(完结)——存储过程、函数+对象曹组
游标 在写java程序中有结果集的概念,那么在pl/sql中也会用到多条记录,这时候我们就要用到游标,游标可以存储查询返回的多条数据。 游标可以理解为是PL/SQL中的结果集,我们通过游标可以提取结果
Java帮帮
2018/03/19
1.9K0
Oracle应用实战八(完结)——存储过程、函数+对象曹组
day44_Oracle学习笔记_03
先去Oracle官网去下载最新版本的sqldeveloper,下载地址:https://www.oracle.com/technetwork/developer-tools/sql-developer/downloads/index.html 得到2个zip压缩包,如下图所示:
黑泽君
2018/10/11
1.8K0
day44_Oracle学习笔记_03
Oracle存储过程和自定义函数
PL/SQL中的过程和函数(通常称为子程序)是PL/SQL块的一种特殊的类型,这种类型的子程序可以以编译的形式存放在数据库中,并为后续的程序块调用。
小小工匠
2021/08/16
8080
Oracle存储过程与存储函数
郭顺发
2023/07/06
6160
Oracle学习笔记四
在写java程序中有集合的概念,那么在pl/sq中也会用到多条记录,这时候我们就要用到游标,游标可以存储查询返回的多条数据。
Kevin_Zhang
2018/09/20
1.4K0
Oracle学习笔记四
​oracle 笔记
一、 oracle介绍 ORACLE 数据库系统是美国 ORACLE 公司(甲骨文)提供的以分布式数据库为核心的一组 软件产品,是目前最流行的客户/服务器(CLIENT/SERVER)或 B/S 体系结构的数据库之一。 比如SilverStream 就是基于数据库的一种中间件。ORACLE 数据库是目前世界上使用最为广泛的数据 库管理系统,作为一个通用的数据库系统,它具有完整的数据管理功能; 作为一个关系数据库, 它是一个完备关系的产品;作为分布式数据库它实现了分布式处理功能。但它的所有知识,只 要在一种机型上学习了ORACLE 知识,便能在各种类型的机器上使用它。
千羽
2021/07/20
9250
​oracle 笔记
【数据库原理与运用|MySQL】MySQL存储过程(详细超全)
云数据库https://cloud.tencent.com/product/cdb
小小程序员
2022/12/22
1.3K0
【数据库原理与运用|MySQL】MySQL存储过程(详细超全)
oracle存储过程相关整理
存储过程是 SQL, PL/SQL, Java 语句的组合, 它使你能将执行商业规则的代码从你的应用程序中移动到数据库。这样的结果就是,代码存储一次但是能够被多个程序使用。是存放在数据库服务器上的SQL语句块,其效率高于同等SQL语句6-10倍
全栈程序员站长
2022/09/07
8630
oracle存储过程相关整理
pl/sql编程---过程、函数、包
1.注释 单行注释 -- select * from emp where empno=7788; --取得员工信息 多行注释 /*...*/来划分 2.标志符号的命名规范 1).当定义变量时,建议用v_作为前缀v_sal 2).当定义常量时,建议用c_作为前缀c_rate 3).当定义游标时,建议用_cursor作为后缀emp_cursor 4).当定义例外时,建议用e_作为前缀e_error 3.块结构示意图 pl/sql块由三个部分构成:定义部分,执行部分,例外处理部分。 如下所示: declare
微醺
2019/01/17
5710
java调用存储过程分页
张哥编程
2024/12/19
1030
java调用存储过程分页
Oracle数据库之第四篇
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
海仔
2019/10/22
9600
java学习:数据增删改查、存储过程调用及事务处理
为了方便,先定义二个常量: package jmyang.utils; public class ConstDefine { /** * WebLogic服务器地址 */ public static final String WebLogicServerUrl = "t3://localhost:7001"; /** * WebLogic JNDI上下文字符串 */ public static final String WebLo
菩提树下的杨过
2018/01/24
1K0
PL/SQL 编程(二)游标、存储过程、函数
游标--数据的缓存区 游标:类似集合,可以让用户像操作数组一样操作查询出来的数据集,实质上,它提供了一种从集合性质的结果中提取单条记录的手段。 可以将游标形象的看成一个变动的光标,他实质上是一个指针,在一段Oracle存放数据查询结果集或者数据操作结果集的内存中,这个指针可以指向结果集任何一条记录。 游标分静态游标和REF游标两类,静态游标包含显式游标和隐式游标。 显式游标: 在使用之前必须有明确的游标声明和定义,这样的游标定义会关联数据查询语句,通常会返回一行或多行。打开游标后,用户可以利用游标的位置对结
二十三年蝉
2018/02/28
3.8K0
Oracle总结【PLSQL学习】
PLSQL介绍 PLSQL是Oracle对SQL99的一种扩展,基本每一种数据库都会对SQL进行扩展,Oracle对SQL的扩展就叫做PLSQL… SQL99是什么 (1)是操作所有关系型数据库的规则 (2)是第四代语言 (3)是一种结构化查询语言 (4)只需发出合法合理的命令,就有对应的结果显示 SQL的特点 (1)交互性强,非过程化 (2)数据库操纵能力强,只需发送命令,无需关注如何实现 (3)多表操作时,自动导航简单,例如: select emp.empno,emp.sal,dept.dname fr
Java3y
2018/03/15
2.4K0
Oracle总结【PLSQL学习】
JDBC实现调用Oracle存储过程
1.关于JDBC (1)什么是JDBC? JDBC的全称是Java Database Connectivity。主要有三个功能: a.建立与数据库的连接和访问任意表格数据源。 b.发送一个SQL声明。 c.处理结果。
星哥玩云
2022/08/16
1.3K0
Oracle基础(五)pl/sql进阶(分页过程)
通过pl/sql实现分页过程,再该过程中由简单到难一步步深入,目的在于通过该案例熟悉pl/sql的各种存储过程,包,游标。怎样在java中调用等内容的学习。
全栈程序员站长
2022/08/27
5950
数据库小技能:存储过程(stored procedure)
过程(procedure)又叫存储过程(stored procedure),是一个有名称的PL/SQL程序块 。
公众号iOS逆向
2022/12/19
7950
相关推荐
快速学习Oracle-存储函数
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验