时间:2023-10-31来源:系统城装机大师作者:佚名
Oracle 存储过程是 Oracle 数据库中的一种数据处理对象,它可以在数据库中定义一组预定义的 SQL 语句,用于完成特定的数据库操作。存储过程可以被授权的用户调用,并且可以执行多个语句,这些语句可以被视为一个单独的操作,也可以被视为一系列的操作。
使用存储过程可以大大提高数据库的性能和安全性。存储过程可以减少网络流量和请求,同时也可以减少与应用程序之间的接口调用,从而提高了数据库的性能和可靠性。
1 2 3 4 5 6 7 8 9 |
-- Created on 2023/5/10 by 肖 declare --声明变量 游标 begin -- 执行语句 -- 异常处理 end ; |
1 2 3 4 5 6 |
begin --打印 hello mr.xiao Dbms_Output.put_line( 'hello mr.xiao' ); end ; |
执行结果
变量分两大类如:
声明变量的方式如:
变量赋值的方式有两种如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
-- 打印个人信息,包括: 姓名、薪水、地址 DECLARE -- 姓名 V_NAME VARCHAR2(30) := '你才是臭弟弟' ; -- 声明变量直接赋值 --薪水 V_SAL NUMBER; --地址 V_ADDR VARCHAR2(200); BEGIN --在程序中直接赋值 V_SAL := 1800; --工资每月1800 每天笑哈哈 --语句赋值 SELECT 'CSDN你才是臭弟弟' INTO V_ADDR FROM DUAL; --不会有人不知道DUAL吧,DUAL 是一个用于描述 Oracle 数据库中的虚拟表的关键字 --打印变量 注意 || 是拼接 DBMS_OUTPUT.PUT_LINE( '姓名:' || V_NAME || ',薪水:' || V_SAL || ',地址:' ||V_ADDR); END ; |
执行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
-- 查询emp表中1001号员工的个人信息,打印姓名和薪水 DECLARE -- 姓名 V_NAME EMP.ENAME%TYPE; -- 声明变量直接赋值 --薪水 V_SAL EMP.ESALARY%TYPE; BEGIN --查询表中的姓名和薪水并赋值给变量 --注意查询的字段和赋值的变量的顺序、个数、类型要一致 SELECT ENAME, ESALARY INTO V_NAME, V_SAL FROM EMP WHERE EMPLOYEEID = 1001; --打印变量 DBMS_OUTPUT.PUT_LINE( '姓名:' || V_NAME || ',薪水:' || V_SAL); END ; |
执行结果:
推荐大家使用引用型变量区别:
总结:
使用普通变量定义方式,需要知道表中列的类型,而使用引用类型,不需要考虑列的类型,使用%TYPE是非常好的编程风格,因为引用型变量更加灵活。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
-- 查询emp表中1001号员工的个人信息,打印姓名和薪水 DECLARE -- 记录型变量接受一行 V_EMP EMP%ROWTYPE; BEGIN --记录型变量默认接受表中的一行数据,不能指定字段。 SELECT * INTO V_EMP FROM EMP WHERE EMPLOYEEID = 1001; --打印变量,通过变量名.属性的方式获取变量中的值 DBMS_OUTPUT.PUT_LINE( '姓名:' || V_EMP.ENAME || ',薪水:' || V_EMP.ESALARY); END ; |
总结:
注意错误的使用案例如下:
我把 * 换成 单个字段执行报错,因为上面的变量定义的是一行,而现在只给一个是不行的。
现在这条sql 为什么报错,因为现在是全表查询 返回的行数超出了 一个变量只能接收一行,这就和JAVA 类似了,应该用集合去装才可以 ,装进集合在取出来 是不是就跟JAVA 中循环取值差不多。
1 2 3 4 5 6 7 |
BEGIN IF 条件 THEN 执行语句 END IF; END ; |
1 2 3 4 5 6 7 8 9 |
BEGIN IF 条件 THEN 执行语句 ELSE 执行语句 END IF; END ; |
1 2 3 4 5 6 7 8 9 10 11 |
BEGIN IF 条件1 THEN 执行1 ELSIF 条件2 THEN 执行2 ELSE 执行3 END IF; END ; |
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
--判断emp表中记录是否超过20条,10-20之间,或者10条以下 DECLARE --声明变量接受emp表中的记录数 V_COUNT NUMBER; BEGIN --查询emp表中的记录数赋值给变量 SELECT COUNT (1) INTO V_COUNT FROM EMP; --判断打印 IF V_COUNT > 20 THEN DBMS_OUTPUT.PUT_LINE( 'EMP表中的记录数超过了20条为:' || V_COUNT || '条。' ); ELSIF V_COUNT >= 10 THEN DBMS_OUTPUT.PUT_LINE( 'EMP表中的记录数在10~20条之间为:' || V_COUNT || '条。' ); ELSE DBMS_OUTPUT.PUT_LINE( 'EMP表中的记录数在10条以下为:' || V_COUNT || '条。' ); END IF; END ; |
执行结果:
1 2 3 4 5 |
BEGIN LOOP EXIT WHEN 退出循环条件 END LOOP; END ; |
Loop语法 案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
--循环打印 1-5 DECLARE --声明循环变量并赋初值 V_NUM NUMBER := 1; BEGIN LOOP EXIT WHEN V_NUM > 5; DBMS_OUTPUT.PUT_LINE(V_NUM); --循环变量自增 V_NUM := V_NUM + 1; END LOOP; END ; |
1 2 3 |
while(判断循环的条件) loop 循环的语句; END loop; |
While语法 案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
DECLARE --声明循环变量 V_NUM NUMBER; BEGIN -- 必须给一个初始值 V_NUM := 1; WHILE(V_NUM < 10) LOOP DBMS_OUTPUT.put_line( '值为: ' || V_NUM); V_NUM := V_NUM + 1; END LOOP; END ; --此循环会先判断再执行语句 |
1 2 3 |
FOR 变量名 in 变量的初始值..结束值 lOOP 循环语句; END loop; |
FOR循环语法 案例:
1 2 3 4 5 6 7 8 9 10 |
--for循环打印 1-10 DECLARE --声明循环变量并赋初值 V_NUM NUMBER ; BEGIN --此语句会自动将1到10赋值给V_NUM FOR V_NUM in 1..10 loop DBMS_OUTPUT.put_line( '值为: ' || V_NUM); END LOOP; END ; |
游标声明:
CURSOR 游标名[(参数列表)] IS 查询语句;
游标的打开:
OPEN 游标名;
游标的取值:
FETCH 游标名 INTO 变量列表;
游标的关闭:
CLOSE 游标名;
注意: 游标名自身是可以带参数的,如果有参数、参数会带入到查询语句中进行查询,游标本质 就是 一个 is 查询语句,也就是说查询结果被放置到游标中。
游标的属性
属性 | 说明 |
%FOUND | 变量最后从游标中获取记录的时候,在结果集中找到了记录。 |
%NOTFOUND | 变量最后从游标中获取记录的时候,在结果集中没有找到记录。 |
%ROWCOUNT | 当前时刻已经从游标中获取的记录数量。 |
%ISOPEN | 是否打开。 |
%ROW | 游标指向的行数。 |
%COLUMN | 游标指向的列数。 |
%ATTEMPTS | 尝试获取记录的次数。 |
%ERROR | 发生错误的次数。 |
%FETCH_STATUS FETCH | 语句的执行状态,包括成功、失败和出错标志。 |
%SIZE | 当前游标指向的记录大小。 |
%LINE_NUMBER | 当前行号。 |
%ERROR_STRING | 错误信息字符串。 |
%PROCID | 当前执行的SQL语句的ID |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
--使用游标查询emp表中所有员工的姓名和工资,依次打印结果集。 DECLARE --声明游标 CURSOR C_EMP IS SELECT ENAME, ESALARY FROM EMP; --声明变量用来接受游标中的元素 V_ENAME EMP.ENAME%TYPE; V_SAL EMP.ESALARY%TYPE; BEGIN --打开游标 OPEN C_EMP; --遍历游标中的值 LOOP --通过FETCH语句获取游标中的值并赋值给变量 FETCH C_EMP INTO V_ENAME, V_SAL; --通过%NOTFOUND判断是否有值,有值打印,没有则退出循环 EXIT WHEN C_EMP%NOTFOUND; DBMS_OUTPUT.PUT_LINE( '姓名:' || V_ENAME || ',薪水:' || V_SAL); END LOOP; --关闭游标 CLOSE C_EMP; END ; |
执行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
--使用游标查询并打印某部门的员工的姓名和薪资,部门编号为运行时手动输入。 DECLARE --声明游标传递参数 CURSOR C_EMP(V_EMPLOID EMP.EMPLOYEEID%TYPE) IS SELECT ENAME, ESALARY FROM EMP WHERE EMPLOYEEID = V_EMPLOID; --声明变量用来接受游标中的元素 V_ENAME EMP.ENAME%TYPE; V_SAL EMP.ESALARY%TYPE; BEGIN --打开游标并传递参数 OPEN C_EMP(1001); --遍历游标中的值 LOOP --通过FETCH语句获取游标中的值并赋值给变量 FETCH C_EMP INTO V_ENAME, V_SAL; --通过%NOTFOUND判断是否有值,有值打印,没有则退出循环 EXIT WHEN C_EMP%NOTFOUND; DBMS_OUTPUT.PUT_LINE( '姓名:' || V_ENAME || ',薪水:' || V_SAL); END LOOP; --关闭游标 CLOSE C_EMP; END ; |
执行结果:
注意:%NOTFOUND属性默认值为FLASE,所以在循环中要注意判断条件的位置.如果先判断在FETCH会导致最后一条记录的值被打印两次(多循环一次默认);
错误反例演示:
反例执行结果:
原因: %NOTFOUND 默认值是 false,false意味着游标里面默认是有值,到底有值还是没值 需要fetch 好之后才知道有没有值,%NOTFOUND 默认做了一个有值的假设 , 看下面代码:
LOOP
--通过%NOTFOUND判断是否有值,有值打印,没有则退出循环
EXIT WHEN C_EMP%NOTFOUND;
--通过FETCH语句获取游标中的值并赋值给变量
FETCH C_EMP
INTO V_ENAME, V_SAL;
DBMS_OUTPUT.PUT_LINE('姓名:' || V_ENAME || ',薪水:' || V_SAL);
END LOOP;
EXIT WHEN C_EMP%NOTFOUND; 判断有值打印,出去之后 又带着有值的进入到循环中 EXIT WHEN C_EMP%NOTFOUND; 判断没值打印, 所以这次打印的是上次值的。注意存放的位置。
参数的类型分为:
1 2 3 4 |
CREATE OR REPLACE PROCEDURE 过程名称[(参数列表)] IS BEGIN END 过程名称; |
1 2 3 4 5 6 7 8 |
--通过调用存储过程打印hello 臭弟弟 CREATE OR REPLACE PROCEDURE P_XIAO IS --声明变量 BEGIN DBMS_OUTPUT.PUT_LINE( 'hello 臭弟弟' ); END P_XIAO ; |
1、is和as都可以用。
2、存储过程中没有declare关键字,declare用在语句块中。也就是说匿名程序才需要, 存储过程没有可以直接带上方--声明变量。
1 2 3 4 5 |
begin --输入调用存储过程的名称 P_XIAO; end ; |
查看结果:
说明:
执行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
--查询并打印某个员工(如:编号1001)的姓名和薪水, 要调用存储过程的时候传入员工编号,自动控制台打印。 CREATE OR REPLACE PROCEDURE P_xiao_jian(IN_EMPLOYEEID IN EMP.EMPLOYEEID%TYPE) as --声明变量接受查询结果 V_ENAME EMP.ENAME%TYPE; V_SAL EMP.ESALARY%TYPE; BEGIN --根据用户传递的员工号查询姓名和薪水 --注意:参数要与定义的参数的顺序和类型一致 如: ENAME INTO V_ENAME SELECT ENAME, ESALARY INTO V_ENAME, V_SAL FROM EMP WHERE EMPLOYEEID = IN_EMPLOYEEID; --打印结果 DBMS_OUTPUT.PUT_LINE( '姓名:' || V_ENAME || ',薪水:' || V_SAL); END P_xiao_jian; |
1 2 3 4 5 6 7 8 9 |
-- Created on 2023/5/13 by 肖 declare -- Local variables here i integer ; begin -- Test statements here P_XIAO_JIAN(1001); --直接赋值 做一个值的传递 end ; |
1 2 3 4 5 6 7 8 9 |
-- Created on 2023/5/13 by 肖 declare -- Local variables here V_PARAM number :=1001; --声明变量 赋值 begin -- Test statements here P_XIAO_JIAN(V_PARAM); end ; |
查看执行结果:
说明:
1 2 3 4 5 6 7 8 9 10 |
--输入员工号查询某个员工(如:编号1001)信息,要求将薪水作为返回值输出,给调用的程序使用。 CREATE OR REPLACE PROCEDURE P_XIAO_JIAN(IN_EMPLOYEEID IN EMP.EMPLOYEEID%TYPE,OUT_ESALARY OUT EMP.ESALARY%TYPE) as BEGIN --查询 ESALARY into 给 OUT_ESALARY 输出变量 SELECT ESALARY INTO OUT_ESALARY FROM EMP WHERE EMPLOYEEID = IN_EMPLOYEEID; END P_XIAO_JIAN; |
1 2 3 4 5 6 7 8 9 10 11 |
DECLARE --声明一个变量接受存储过程的输出参数 V_ESALARY EMP.ESALARY%TYPE; BEGIN P_XIAO_JIAN(1001, V_ESALARY); --注意参数的顺序 DBMS_OUTPUT.PUT_LINE( '工资:' ||V_ESALARY); END ; |
执行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
--输入员工号查询某个员工(如:编号1001)信息,要求将薪水作为返回值输出,给调用的程序使用。 CREATE OR REPLACE PROCEDURE P_xiao_jian(IN_EMPLOYEEID IN EMP.EMPLOYEEID%TYPE,OUT_ESALARY OUT EMP.ESALARY%TYPE,IN_OUT_PARAM in out number) as BEGIN --查询 ESALARY into 给 OUT_ESALARY 输出变量 SELECT ESALARY INTO OUT_ESALARY FROM EMP WHERE EMPLOYEEID = IN_EMPLOYEEID; --打印被传入的值 dbms_output.put_line( '我是被传入的值' ||IN_OUT_PARAM); --IN_OUT_PARAM赋值默认值为10 IN_OUT_PARAM:=10; END P_xiao_jian; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
-- Created on 2023/5/16 by 肖 declare -- Local variables here V_ESALARY EMP.ESALARY%TYPE; V_IN_OUT_PARAM number:=6; --传入的值 begin -- Test statements here P_xiao_jian(1001,V_ESALARY,V_IN_OUT_PARAM); DBMS_OUTPUT.PUT_LINE( '薪水:' ||V_ESALARY|| '原始默认值: ' ||V_IN_OUT_PARAM); end ; |
执行结果:
以上就是一文详解Oracle存储过程的详细内容,
2023-10-31
Oracle如何编写一个sqlldr实例2023-10-31
Oracle的SQLLDR用法简介2023-10-31
Oracle中的高效SQL编写PARALLEL解析1.Oracle数据库系统结构概述 2.Oracle数据库存储结构 物理存储结构 控制文件 数据文件 重做日志文件 归档日志文件 Oracle数据库逻辑结构 数据块(Data Block) (盘)区(Extent) 段(Segment) 表空间(Tablespace) 本地管...
2023-10-31
windows下的Oracle19c 一、官网下载Oracle19c数据库 二、安装Oracle数据库 1.解压安装包 2.运行setup.exe安装 三、配置 四、安装完Oracle数据库,给scott用户解锁 1.解决Oracle数据库中没有scott账户的问题 2.给scott...
2023-10-31