存储过程和自定义函数
1 . 存储过程和自定义函数的区别:
① 功能不同,存储过程主要用于数据同步,而自定义函数主要用于做计算。
② 调用方式不同,存储过程一般使用 BEGIN END 调用,而自定义函数是放在 SELECT 语句后面调用的。
③ 返回值不同, 存储过程不需要返回结果,而自定义函数必须返回一个计算结果。
④ 定义时不同,存储过程不需要指明返回值的数据类型,自定义函数必须指定返回值的数据类型。
2 . 创建存储过程和自定义函数的语法:
①创建存储过程语法规则:
CREATE OR REPLACE PROCEDURE SP_过程名(参数1 [IN|OUT|IN OUT] 数据类型,
参数2 [IN|OUT|IN OUT] 数据类型…)
IS /*|AS*/
BEGIN
执行体
END ;
②创建自定义函数语法规则:
CREATE OR REPLACE FUNCTION FUN_函数名(参数1 数据类型,
参数2,[IN|OUT|IN OUT] 数据类型……)
RETURN 返回的数据类型,不写长度
IS /*|AS*/
BEGIN
执行体
RETURN 结果; --里面必须要有一个RETURN子句
END ;
3. 过程和函数的参数类型 [IN|OUT|IN OUT]
IN 类型为 输入参数,默认参数,可以不写。【不能重新赋值】
OUT 类型为 输出参数。【可以被重新赋值,但是不会接受输入的参数】
IN OUT 类型为输入输出参数,既可以接受传入的值,也可以作为输出参数输出结果。【可以被重新赋值】
------------------------------------------ IN 参数 ----------------------------------------------
- 定义一个存储过程 使用 in 参数类型实现,
接收员工的 编号,打印出员工的 入职时间和社保缴纳日期,显示为字符格式 (YYYY-MM)
① 创建存储过程
CREATE OR REPLACE PROCEDURE SP_EMP(P_EMPNO IN NUMBER)
IS
V_HD DATE;--入职时间
V_JD VARCHAR2(8);--社保缴纳时间
BEGIN
SELECT E.HIREDATE , --入职时间
TO_CHAR( ROUND(E.hiredate,'MM') ,'YYYY-MM') JD --社保缴纳时间
INTO V_HD ,V_JD
FROM EMP E
WHERE E.EMPNO = P_EMPNO;--传入员工编号
DBMS_OUTPUT.PUT_LINE(TO_CHAR(V_HD,'YYYY-MM-DD')||' '||V_JD);
END ;
② 调用存储过程
BEGIN
SP_EMP(7369);
END ;
- 定义一个自定义函数 使用 in 参数类型实现,
接收员工的 编号,返回员工的社保缴纳日期,显示为字符格式 (YYYY-MM)
① 自定义函数
CREATE OR REPLACE FUNCTION FUN_EMP(P_EMPNO IN NUMBER)
RETURN VARCHAR2
IS
V_JD VARCHAR2(8);--社保缴纳日期
BEGIN
SELECT TO_CHAR( ROUND(E.hiredate,'MM') ,'YYYY-MM')
INTO V_JD
FROM EMP E
WHERE E.empno = P_EMPNO;
RETURN V_JD;
END ;
② 调用自定义函数
SELECT E.* ,
FUN_EMP(E.empno) 社保缴纳年月
FROM EMP E;
------------------------------------------ OUT 参数 ---------------------------------------------
OUT****类型为 输出参数。【可以被重新赋值,但是不会接收任何 传入/输入的值】
并且,一旦定义了 OUT 类型的参数,调用过程时,必须传入一个 变量,不传会报错。
①创建存储过程
CREATE OR REPLACE PROCEDURE SP_HELLOWORLD (P_STR OUT VARCHAR2)
IS
BEGIN
P_STR := '不听不听,除非买包';
DBMS_OUTPUT.PUT_LINE('HELLO WORLD');
DBMS_OUTPUT.PUT_LINE('HELLO '||P_STR);
END ;
②调用存储过程
DECLARE
V_STR VARCHAR2(30) := '包太贵,买口红吧' ;
BEGIN
SP_HELLOWORLD(V_STR);
END ;
---------------------------------------------- IN OUT 参数 ----------------------------------------------
IN OUT 类型的参数,既可以接收传入的值 ,又可以把该参数作为 输出的对象
比如 接收员工的姓名,打印出该员工的 岗位
①创建存储过程
CREATE OR REPLACE PROCEDURE SP_ENAME_JOB(P_NAME_JOB IN OUT VARCHAR2)
IS
-- 这里不需要单独定义输出的变量。因为可以对 输入输出参数重新赋值。
BEGIN
SELECT JOB
INTO P_NAME_JOB -- 对 out 类型的参数进行重新赋值,并最后打印出来
FROM EMP
WHERE ENAME = P_NAME_JOB; -- 使用参数接收的姓名作为条件
DBMS_OUTPUT.PUT_LINE(P_NAME_JOB);
END ;
②调用存储过程
DECLARE
V_ENAME VARCHAR2(10) :='SCOTT';
BEGIN
SP_ENAME_JOB(V_ENAME);
END ;
对比 IN 和 IN OUT 类型的参数
①创建存储过程
CREATE OR REPLACE PROCEDURE SP_JOB(P_NAME VARCHAR2)
IS
V_JOB VARCHAR2(10);
BEGIN
SELECT JOB
INTO V_JOB
FROM EMP
WHERE ENAME = P_NAME;
DBMS_OUTPUT.PUT_LINE(V_JOB);
END ;
②调用存储过程
BEGIN
SP_JOB('SCOTT');
END ;
【例】查询20部门中的经理的姓名、工资、入职日期。
①创建存储过程
CREATE OR REPLACE PROCEDURE SP_MYEMP( P_DEPTNO IN NUMBER,
P_HIREDATE OUT DATE,
P_JOB_ENAME IN OUT VARCHAR2)
AS
----------参数不能定义长度
V_SAL NUMBER;--声明变量V_SAL
BEGIN
SELECT E.ENAME,--姓名
E.SAL, --工资
E.HIREDATE --入职日期
INTO P_JOB_ENAME, -- P_JOB_ENAME 这里是姓名
V_SAL,
P_HIREDATE
FROM EMP E
WHERE E.DEPTNO = P_DEPTNO
AND E.JOB = P_JOB_ENAME; -- P_JOB_ENAME 是岗位
DBMS_OUTPUT.PUT_LINE(P_JOB_ENAME || ' ' || V_SAL || ' ' || TO_CHAR(P_HIREDATE,'YYYY/MM/DD'));
END;
②调用存储过程
DECLARE
V_date DATE;--OUT类型,声明变量传入参数
V_JOB VARCHAR2(10) :='MANAGER';
BEGIN
SP_MYEMP(20,V_date,V_JOB);
END ;
总结:
- 在过程或者函数中定义了参数,就必须传值
- IN 类型的参数,不能通过变量传值,必须直接传值[可以是数字 字符 日期
- 带了 OUT 类型的参数,必须通过变量传参,无论是 OUT 或者 IN OUT
- OUT 类型的参数,虽然不接收传入的参数,但是跟第一条一样,必须给它一个变量,哪怕变量的值是空的。
- IN OUT 类型的参数,也需要通过变量传参,同时 IN OUT 类型的参数,可以像变量一样输出或者被重新赋值。