简称“存储”或者“存过”,是一种命名的PL/SQL程序。存储过程会依据输入参数来决定程序如何运行,而且在调用结束时,存储过程还可根据程序运行情况返回一些输出参数
①语法:
--------------存储过程---------------
CREATE [OR REPLACE] PROCEDURAL PRO_NAME [(PARA1,PARA2...)]
AS|AS
VAR_NAEM VAR_TYPE;
...
BEGIN
PLSQL_SENTENCE
EXCEPTION
EXCEPT_SENTENCE
END [PRO_NAME];
--CREATE创建过程 OR REPLACE 替换一个过程
②编译:
存储过程代码写完后需要点击执行,执行的是编译的过程,也就是写入数据库的过程,编译后的存储过程可以在工具的左侧产看编译状态。有问题会出现 “x” 号。
注意:
注意 : 存储过程中的DDL语句权限问题:数据库当前用户授予了connect、resource权限,在存储过程里面执行execute immediate 'create table XX’时会报“权限不足”的错误。resource角色是具有create table的权限的,为什么在存储过程里面创建表就权限不足了。原因为:用户拥有的角色role在存储过程里面不可用。 必须授予一个一个的权限才会起作用即不能授予角色
解决办法:
begin table_rebuiled_emp; end;
对于形式参数的约束:在过程或者函数的声明中char、varchar2的长度以及number的范围,精度都是非法的
(1)IN模式参数
语法:
--in模式参数
CREATE OR REPLACE PROCEDURE PRO_NAME(
I_NAME1 [IN] DATA_TYPE DEFAULT DEF_VAL,
I_NAME2 [IN] DATA_TYPE DEFAULT DEF_VAL,
...
)
IS|AS
--可以设置默认值,供无实参录入时使用
-- in参数只能存储默认值过或方法传值
--存储过程-参数传递方法
--名称传递
PRO_NAME(I_NAME1=>,I_NAME2,...)
--位置传递
pro_name(value1,value2)
--混合传递法
pro_name(value1,i_name2=>value2)
--注意只有名称传递才能更改原参数位置顺序
--混合传递法中但凡某位置用了名称传递,后续都要用名称传递
(2)out模式参数 --一般不用
代码实现:
--out模式参数:输出类型的参数 一般不用
CREATE OR REPLACE PROCEDURE
SP_EMP_SAL(V_RATE NUMBER,V_NAME VARCHAR2,V_SAL OUT NUMBER)
IS
BEGIN
UPDATE EMP SET SAL=SAL*(1+V_RATE) WHERE ENAME=V_NAME;
COMMIT;
SELECT SAL INTO V_SAL FROM EMP WHERE ENAME=V_NAME;
END SP_EMP_SAL;
DECLARE
A NUMBER;
BEGIN
SP_EMP_SAL(0.5,'SMITH',A);
DBMS_OUTPUT.PUT_LINE(A);
END;
(3)in out 参数模式
代码实现:
-- IN OUT 模式参数
CREATE OR REPLACE PROCEDURE
SP_EMP_SAL(V_RATE IN OUT NUMBER,V_NAME VARCHAR2)
IS
BEGIN
UPDATE EMP SET SAL=SAL*(1+V_RATE) WHERE ENAME=V_NAME;
COMMIT;
SELECT SAL INTO V_RATE FROM EMP WHERE ENAME=V_NAME;
END SP_EMP_SAL;
DECLARE
V_RATE NUMBER:=0.5;
V_NAME VARCHAR2(300):='SMITH';
BEGIN
SP_EMP_SAL(V_RATE,V_NAME);
DBMS_OUTPUT.PUT_LINE(V_RATE);
END;
④删除存储过程:
drop procedure 存储过程名
存储函数与存储过程语法很相似,区别:
语法:
CREATE [OR REPLACE] FUNCTION FUN_NAME [(PARA1,PARA2...)]
RETURN DATATYPE
AS|IS
VAR_NAME VAR_TYPE;
...
BEGIN
PLSQL_SENTENCE
RETURN VAR_NAME;
EXCEPTION
EXCEPT_STENTENCE
END [FUN_NAME];
调用:
select fun_name(para) from dual;
删除:
drop function fun_name;
结构:
EXCEPTION
WHEN ERR_NAME1 TEHN
EXCEPT_SENTENCE1
WHEN ERR_NAME2 TEHN
EXCEPT_SENTENCE
...
WHEN OTHERS TEHN
EXCEPT_SENTENCEN
预定义:
BEGIN
plsql_sentence
EXCEPTION
WHEN ERR_NAEM THEN
EXCEPT_SENTENCE
END;
--预定义异常在使用时完全不需要用户声明,由ORACLE自行引发自行判定
代码实现:
DECLARE
A EMP.ENAME%TYPE;
BEGIN
DBMS_OUTPUT.PUT_LINE('程序执行开始......');
SELECT ENAME INTO A FROM EMP WHERE DEPTNO=60;
DBMS_OUTPUT.PUT_LINE(A);
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('试图将多个数据赋给一个变量');
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('没有任何数据');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('程序出错!');
-- RAISE; -- 将发生的异常以原来默认弹框显示
END;
非预定义异常:
DECLARE
ERR_NAEM EXCEPTION;
REAGME EXCEPTION_INIT(ERR_NAME,ERR_CODE);
BEGIN
PLSQL_SENTENCE
EXCEPTION
WHEN ERR_NAME THEN
EXCEPT_SENTENCE
END;
代码实现:
DECLARE
-- 1.定义非预定义异常
E_FK EXCEPTION;
-- 2.把ORACLE错误与异常建立关联
-- -2292 违反外键约束的错误编号
PRAGMA EXCEPTION_INIT(E_FK,-2292);
BEGIN
DELETE FROM DEPT WHERE DEPTNO = &DEPTNO;
EXCEPTION
WHEN E_FK THEN
-- 3.捕捉并处理异常
DBMS_OUTPUT.PUT_LINE('此部门下有员工,无法删除!');
WHEN OTHERS THEN
-- SQLCODE 获得ORACLE错误编号,SQLERRM获取ORACLE错误信息
DBMS_OUTPUT.PUT_LINE(SQLCODE||'###'||SQLERRM);
END;
自定义异常:
DECLARE
ERR_NAME EXCEPTION;
BEGIN
IF <CONDITION_EXPRESSION1> THEN
RAISE ERR_NAME;
END IF;
PLSQL_SENTENCE
EXCEPTION
WHEN ERR_NAME THEN
EXCEPT_SENTENCE
END;
注意:
代码实现
--自定义异常 不对异常进行处理要处理必须为异常起名字
DECLARE
V_COMM EMP.COMM%TYPE;
BEGIN
SELECT COMM INTO V_COMM FROM EMP WHERE EMPNO=7788;
IF V_COMM IS NULL THEN
RAISE_APPLICATION_ERROR('-20010','该雇员无补助');
END IF;
END;
--自义定异常
DECLARE
V_COMM EMP.COMM%TYPE;
E_COMM_IS_NULL EXCEPTION;--定义异常类型变量
BEGIN
SELECT COMM INTO V_COMM FROM EMP WHERE EMPNO=7788;
IF V_COMM IS NULL THEN
RAISE E_COMM_IS_NULL; -- 抛出一个自定义异常,如果发生异常就会调转到EXCEPTION部分
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('雇员不存在!错误为:'||SQLCODE||SQLERRM);
WHEN E_COMM_IS_NULL THEN --处理自定义异常
DBMS_OUTPUT.PUT_LINE('该雇员无补助 ');
-- RAISE_APPLICATION_ERROR(-20001,'该员工没有奖金'); --为异常绑定一个编号并 以弹窗形式弹出错误信息
END;