目录
1、名词释义
2、创建语法
3、系统异常
4.1、无参存储过程
4.2、带参数存储过程
4.3、带if的存储过程
4.4、带if else的存储过程
4.5、带else if的存储过程
4.6、带while循环的存储过程
4.7、带select into的存储过程
存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,是由流程控制和SQL语句书写的命名语句块。
Oracle存储过程包含三部分:过程声明,执行过程部分,存储过程异常。
CREATE [OR REPLACE] PROCEDURE 存储过程名(PARAM1 IN TYPE,PARAM2 OUT TYPE)
AS --as和is任选一个,在这没有区别
变量1 类型(值范围);
变量2 类型(值范围);
BEGIN
SELECT COUNT(*) INTO 变量1 FROM 表A WHERE列名=PARAM1;
IF (判断条件) THEN
SELECT 列名 INTO 变量2 FROM 表A WHERE列名=PARAM1;
DBMS_OUTPUT.PUT_LINE(‘打印信息’);
ELSIF (判断条件) THEN
DBMS_OUTPUT.PUT_LINE(‘打印信息’);
ELSE
RAISE 异常名(NO_DATA_FOUND);
END IF;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;
ACCESS_INTO_NULL | 未定义对象 |
CASE_NOT_FOUND | CASE 中若未包含相应的 WHEN ,并且没有设置ELSE 时 |
COLLECTION_IS_NULL | 集合元素未初始化 |
CURSER_ALREADY_OPEN | 游标已经打开 |
DUP_VAL_ON_INDEX | 唯一索引对应的列上有重复的值 |
INVALID_CURSOR | 在不合法的游标上进行操作 |
INVALID_NUMBER | 内嵌的 SQL 语句不能将字符转换为数字 |
NO_DATA_FOUND | 使用 select into 未返回行,或应用索引表未初始化的 |
TOO_MANY_ROWS | 执行 select into 时,结果集超过一行 |
ZERO_DIVIDE | 除数为 0 |
SUBSCRIPT_BEYOND_COUNT | 元素下标超过嵌套表或 VARRAY 的最大值 |
SUBSCRIPT_OUTSIDE_LIMIT | 使用嵌套表或 VARRAY 时,将下标指定为负数 |
VALUE_ERROR | 赋值时,变量长度不足以容纳实际数据 |
LOGIN_DENIED | PL/SQL 应用程序连接到 oracle 数据库时,提供了不正确的用户名或密码 |
NOT_LOGGED_ON | PL/SQL 应用程序在没有连接 oralce 数据库的情况下访问数据 |
PROGRAM_ERROR | PL/SQL 内部问题,可能需要重装数据字典& pl./SQL系统包 |
ROWTYPE_MISMATCH | 宿主游标变量与 PL/SQL 游标变量的返回类型不兼容 |
SELF_IS_NULL | 使用对象类型时,在 null 对象上调用对象方法 |
STORAGE_ERROR | 运行 PL/SQL 时,超出内存空间 |
SYS_INVALID_ID | 无效的 ROWID 字符串 |
TIMEOUT_ON_RESOURCE | Oracle 在等待资源时超时 |
--1)无参存储过程语法
CREATE OR REPLACE PROCEDURE PRO_1_NOPAR
AS --声明
BEGIN --执行
--SELECT * FROM D_DEPT D;
DBMS_OUTPUT.PUT_LINE('无参存储过程');
EXCEPTION--异常
WHEN OTHERS THEN
ROLLBACK;
END;
--调用
BEGIN
PRO_1_NOPAR;
END;
IN表示输入参数,是参数的默认模式。
OUT表示返回值参数,类型可以使用任意Oracle中的合法类型。
OUT模式定义的参数只能在过程体内部赋值,表示该参数可以将某个值传递回调。
IN OUT表示该参数可以向该过程中传递值,也可以将某个值传出去。
--2)带参数存储过程含赋值方式
CREATE OR REPLACE PROCEDURE PRO_2_PAR
(VAL IN NUMBER,
SNAME OUT VARCHAR,
DT_CODE IN OUT VARCHAR)
AS
ICOUNT NUMBER;
BEGIN
SELECT COUNT(*) INTO ICOUNT FROM D_DEPT WHERE DT_ID>VAL;
IF ICOUNT=1 THEN
SNAME:= 'MLB事业部1' ||VAL;
DT_CODE:= 'MLB1'||DT_CODE;
ELSE
SNAME:= 'MLB事业部2'||VAL;
DT_CODE:= 'MLB2'||DT_CODE;
END IF;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('返回值多于1行');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('在PRO_1_PAR过程中出错!');
END;
--调用
declare
REVAL NUMBER;
RENAME varchar(40);
RECODE varchar(40);
begin --过程调用开始
REVAL:=20210421;
RENAME:='';
RECODE:='JUNIOR';
--指定值对应变量顺序可变
PRO_2_PAR(SNAME=>RENAME,VAL=>REVAL,DT_CODE=>RECODE);
DBMS_OUTPUT.PUT_LINE(RENAME||' '||RECODE);
END; --过程调用结束
--3)带if的存储过程
CREATE OR REPLACE PROCEDURE PRO_3_IF(A IN NUMBER, B IN NUMBER,RS OUT NUMBER)
AS
TEMP NUMBER;
BEGIN
TEMP:=A;
IF A < B THEN
TEMP := B;
END IF;
RS:=TEMP;
END;
--调用
DECLARE
RS NUMBER;
BEGIN
PRO_3_IF(10,20,RS);
DBMS_OUTPUT.PUT_LINE('RS='||RS);
END;
CREATE OR REPLACE PROCEDURE PRO_4_IFELSE(A IN NUMBER, B IN NUMBER,RS OUT NUMBER)
AS
BEGIN
IF A > B THEN
RS := A;
ELSE
RS := B;
END IF;
END;
--调用
DECLARE
RS NUMBER;
BEGIN
PRO_4_IFELSE(30,20,RS);
DBMS_OUTPUT.PUT_LINE('RS='||RS);
END;
CREATE OR REPLACE PROCEDURE PRO_5_ELSEIF(Y IN NUMBER)
AS
BEGIN
IF Y=2020 THEN
DBMS_OUTPUT.PUT_LINE('2020年');
ELSIF Y =2021 THEN
DBMS_OUTPUT.PUT_LINE('2021年');
ELSE
DBMS_OUTPUT.PUT_LINE('未知年份');
END IF;
END;
--存储过程调用
BEGIN
PRO_5_ELSEIF(Y => 2021);
END;
--6)带while循环的存储过程
CREATE OR REPLACE PROCEDURE PRO_6_WHILE(I IN NUMBER)
AS
J NUMBER;
BEGIN
J := 1;
WHILE J <= I LOOP
DBMS_OUTPUT.PUT_LINE('J='||J);
J := J + 1;
END LOOP;
END;
--存储过程调用
BEGIN
PRO_6_WHILE(I=> 100);
END;
在利用SELECT…INTO…语法时,必须先确保数据库中有该条记录,否则会报出"NO_DATA_FOUND"异常。
可先利用SELECT COUNT(*) FROM 查看数据库中是否存在该记录,存在则使用SELECT…INTO。
在存储过程中,别名不能和字段名称相同,否则虽然编译可以通过,但在运行阶段会报错。
--7)带SELECT INTO的存储过程
CREATE OR REPLACE PROCEDURE PRO_7_SELINTO(ID IN NUMBER)
AS
M VARCHAR(50);
G VARCHAR(50);
BEGIN
SELECT MONTH,ORG_OID INTO M,G FROM D_DEPT where DT_ID=ID;
DBMS_OUTPUT.PUT_LINE('M'||M||'G'||G);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('NO_DATA_FOUND异常');
END;
--存储过程调用
BEGIN
PRO_7_SELINTO(ID=> 21);
END;