ORACLE数据库 —— PL/SQL知识点3

ORACLE数据库  PL/SQL语句基础知识点  适合有SQL基础的人群。 禁止转载!

存储过程
    声明部分:包括类型、变量和游标
    执行部分:完成功能而编写的SQL语句或是PL/ SQL代码块
    异常处理部分

创建存储过程基本语法:
    CREATE [OR REPLACE] PROCEDURE procedure_name
        [(parameter_name [IN|OUT|IN OUT] datetype 
        [DEFAULT datavalue] 
        [,...])]
        {IS|AS}    
        [variable type [,...]]
    BEGIN
        procedure_body
    EXCEPTION
    END [procedure_name];


删除过程基本语法
    DROP PROCEDURE procedure_name;

调用过程基本方式
    可以使用EXECUTE指令调用过程,也可以在PL/SQL代码块中直接调用过程(不加EXECUTE)。

eg.1通过存储过程查询不同部门的人员数。
CREATE OR REPLACE PROCEDURE pro_count_dept(var_deptno emp.deptno%type)

AS var_count NUMBER;                                                       //带参数的存储过程

BEGIN
    SELECT count(*) INTO var_count FROM emp WHERE
    deptno = var_deptno;                //存储过程自带参数var_deptno  DECLARE部分已经声明
    DBMS_OUTPUT.PUT_LINE('部门号'||var_deptno||'的员工人数是'||var_count);
    EXCEPTION WHEN NO_DATA_FOUND then 
    dbms_output.put_line('没有数据');
END;
/        

执行存储过程
    法1.使用 EXECUTE pro_count_dept(10)                         //自带参数10
    法2.PL/SQL代码块中直接调用过程    
        BEGIN
             pro_count_dept(10)                        //自带参数10
        END;


参数基本语法说明
    IN: 向存储过程传递参数, 只能将实参的值传递给形参。
    OUT: 从存储过程输出参数, 存储过程结束时形参的位会赋    给实参。
    IN OUT: 具有前面两种模式的特性, 调用时, 实参的位传递给形参, 结束时, 形参的值传递给实参。

eg2.通过存储过程,利用雇员编号查询雇员雇用日期(out举例)
CREATE OR REPLACE PROCEDURE pro_query_hiredate
(var_empno empno%type,
 var_hiredate out hiredate%type)
AS
BEGIN
    SELECT hiredate INTO var_hiredate  FROM emp WHERE empno = varempno;
END;

pro_query_hiredate(v_empno,v_hiredate)的调用过程:
DECLARE
    v_empno empno%type
    v_hiredate hiredate%type
BEGIN
    v_empno:=&empno;                //手动输入empno
    pro_query_hiredate(v_empno,v_hiredate);        //调用存储过程
    dbms_output.put_line('编号为'||v_empno||'的员工雇佣日期是'|| to_char(v_hiredate,'yyyy-mm-dd'));
    EXCEPTION WHEN NO_DATA_FOUND THEN
        dbms_output.put_line('查无此人');

END;
/

eg3.通过存储过程,交换两个数据的值(in out举例)
DECLARE OR REPLACE PROCEDURE pro_swap
    (var_num1 IN OUT NUMBER,
     var_num2 IN OUT NUMBER)
AS
    temp number;
BEGIN
    temp:=var_num1;
    var_num1:=var_num2;
    var_num2:=temp;
END;

pro_swap(var_num1,var_num2)的调用过程:
DECLARE
    var_num1 number;
    var_num2 number;
BEGIN 
    var_num1:=&var_num1;
    var_num2:=&var_num2;
    pro_swap(var_num1,var_num2);
    dbms_output.put_line('new_num1值为'||v_num1||';new_num2值为'||v_num2);
END;
/


函数
创建函数基本语法:
    CREATE [OR REPLACE] FUNCTION function_name
        [(parameter_name [IN|OUT|IN OUT] type [,...])]
    RETURN type                       //函数的返回类型   不可缺少!!!
    {IS|AS}

    [variable type [,...]]
    BEGIN
        function_body
    END function_name;

删除函数语法:
    DROP FUNCTION function_name;

eg4.创建一个函数,以雇员编号查询雇员薪水
CREATE OR REPLACE FUNCTION ft_query_sal(var_empno empno%type)
RETURN NUMBER AS        //函数的返回类型是NUMBER
var_sal NUMBER;
BEGIN
    SELECT sal INTO var_sal FROM emp WHERE empno=var_empno;
    RETURN var_sal;
END;

函数ft_query_sal(v_empno)的调用过程:
DECLARE
    v_empno empno%type;
    v_sal sal%type;
BEGIN
    v_empno:=&empno;
    --使用声明变量接收函数返回值
    v_sal:=ft_query_sal(v_empno);
    dbms_output.put_line('编号为'||v_empno||'的员工薪水是'||To_char(v_sal));
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            dbms_output.put_line('查无此人');
END;
/

包          ----------包是由存储在一起的相关对象组成的PL/SQL结构。用于逻辑组合相关的自定义类型、变量、游标、过程和函数。 
              --------包分为包头(包规范)和包体,缺一不可。

包规范基本语法:
    CREATE [OR REPLACE] PACKAGE package_name
    {IS|AS}
        公用类型或变量常量的声明;
        公用过程或函数的声明;
    END package_name;

包主体基本语法:
    CREATE [OR REPLACE] PACKAGE BODY package_name
    {IS|AS}
        私有类型或变量常量的声明;
        公有过程或函数的声明;
    END package_name;

调用包中的函数和过程时,应该调用中使用包名:
    语法:package_name.type_name;

eg5.将过程pro_count_dept、函数ft_query_sal放入包pa_mypack中,以便对代码进行管理和调用,如何实现?


    1. 包规范的书写(类似于C语言中的.h文件)
        CREATE OR REPLACE PACKAGE pa_mypack
        AS
            PROCEDURE pro_count_dept(var_deptno deptno%type);
            FUNCTION ft_query_sal(var empno empno%type) RETURN NUMBER;
        END pa_mypack;


    2. 包体的书写(类似于C语言中的.c文件)
        CREATE OR REPLACE PACKAGE BODY pa_mypack
        AS
            -- 实现过程pro_count_dept
            PROCEDURE pro_count_dept(var_deptno emp.deptno%type) AS var_count NUMBER;
            BEGIN
                SELECT count(*) INTO var_count FROM emp WHERE deptno = var_deptno;
                dbms_output.put_line('部门号'||var_deptno||'的员工人数是'||var_count);
            EXCEPTION
                WHEN NO_DATA_FOUND then dbms_output.put_line('没有数据');
            END;
            -- 实现函数ft_query_sal
            FUNCTION ft_query_sal(var_empno empno%type) RETURN NUMBER 
            AS    var_sal number;
            BEGIN
                SELECT sal INTO var_sal FROM emp WHERE empno=var_empno;
                RETURN var_sal;
            END;
        END pa_mypack;

调用pa_mypack:
    DECLARE
        v_empno emp.empno%type;
        v_sal emp.sal%type;
        v_deptno emp.deptno%type;
    BEGIN
        v_empno:=&empno;
        v_deptno:=&deptno;
        pro_count_dept(v_deptno);
        v_sal:=pa_mypack.ft_query_sal(v_empno);
        dbms_output.put_line('编号为'||v_empno||'的员工薪水是'||To_char(v_sal));
        EXCEPTION WHEN NO_DATA_FOUND THEN 
            dbms_output.put_line('无此人薪水信息');
    END;
    /

查看过程,函数和包的有关信息:
    DESC user_procedures;
    SELECT * FROM user_procedure WHERE object_name = 'PRO_QUERY_HIREDATE';

查看过程或函数代码:
    SELECT text FROM user_source WHERE name='PRO_COUNT_DEPT';

查看包代码:
    SELECT text FROM user_source WHERE name='PA_MYPACK' AND type='PACKAGE';


触发器       -----是一种特殊的过程。当特定的事件发生时,触发器被自动执行。

建立DML触发器的基本语法:
    CREATE [OR REPLACE] TRIGGER trigger_name
    {BEFORE|AFTER} trigger_event                //trigger_event   有   insert、update、delete
    ON table_name                                             //table_name  就是被操作的那个表的名字

    [REFERENCING [OLD AS old_name][NEW AS new_name]]
    [WHEN trigger_condition]
    [FOR EACH ROW]
    [DECLARE]
    BEGIN
        trigger_body
    END trigger_name;

eg6.记录下所有更改newemp表的用户名,操作类型和更改时间。
    CREATE OR REPLACE TRIGGER tr_iud_newemp
    BEFORE insert or update or delete
        ------插入、更新、删除前调用

    ON newemp;

        -------对newemp进行操作的时候
    DECLARE 
        v_operate scott.log_iud_newemp.operate_name%type;
    BEGIN
        IF inserting then 
            v_operate:='insert'; 
        END IF;
        IF updating then
            v_operate:='update';
        END IF;
        IF deleting then
            v_operate:='delete';
        END IF;

        INSERT INTO log_iud_newemp VALUES (user,to_char(sysdate,'YYYY-MM-DD HH-MI-SS'),v_operate);
    END;
    /

触发器的禁用、启用与删除:
    ALTER TRIGGER my_trig {DISABLE|ENABLE};            //禁用/启用单个触发器
    ALTER TABLE trig_table {DISABLE|ENABLE} ALL TRIGGERS;        //禁用/启用trig_table表的所有触发器
    DROP TRIGGER my_trig;                    //删除
        
查看触发器信息:
    SELECT trigger_name,table_name FROM user_triggers;

行级触发器:执行DML语句时,每操作一行,触发器就执行一次。行级触发器使用WHEN条件,用于控制触发器的执行。
         For each row

行级触发器引入两个标识符::old和:new
        :old表示原有的数据         :new表示新修改的数据

eg7.创建一个行级触发器,为表的主键列生成自增序列号
    1、生成一个表。
        CREATE TABLE employee(id number(10) primary key,name varchar2(20));
    2、生成一个序列。
        CREATE SEQUENCE id_seq;
    3、创建行级触发器。
        CREATE OR REPLACE TRIGGER tr_insert_employee_for_pk
        BEFORE insert
        on employee
        for each row
        BEGIN
            SELECT id_seq.nextval into :new.id FROM dual;
        END;


instead of 触发器:只能定义在视图上,用于执行一个替代操作来代替对视图的操作,对视图操作最终会转换为基本表的操作。
    instead of 触发器必须是行级触发器。

创建基本语法:
    CREATE [OR REPLACE] TRIGGER trigger_name
    INSTEAD OF trigger_event
    ON view_name
    [REFERENCING [OLD AS old_name][NEW AS new_name]]
    [WHEN trigger_condition]
    [FOR EACH ROW]
    [DECLARE]
    BEGIN
        trigger_body
    END trigger_name;

eg8.Instead of 触发器更新一个视图
    --创建instead of触发器
    CREATE OR REPLACE TRIGGER tr_ins_view_newemp_newdept
    INSTEAD OF insert ON view_newemp_newdept
    FOR EACH ROW
    DECLARE
        rowcat number;
    BEGIN
        SELECT count(*) into rowcat FROM newdept WHERE 
        deptno=:new.deptno;
        IF rowcat=0 THEN 
            begin
                INSERT INTO newdept(deptno) VALUES (:new.deptno);
                INSERT INTO newemp (empno,ename,job,deptno) VALUES
                (:new.empno,:new.ename,:new.job,:new.deptno);
            end;
        ELSE
            INSERT INTO newemp (empno,ename,job,deptno)VALUES(:new.empno,:new.ename,:new.job,:new.deptno);
        END IF;
    END;
    /


系统触发器:
    系统触发器的激活基于两种不同的事件:
        DDL事件: CREATE、 ALTER、 DROP、TRUNCATE,…
        数据库事件:数据库服务器的启动/关闭事件、用户的登录/断开事件、服务器错误


显示错误:查看出现的错误,可以使用SHOW ERRORS命令,这只适用于当前只编译了一个存储过程的情况。
    SHOW ERRORS

在编译了多个存储过程或函数的情况下,可以把SHOW ERRORS更为细化:
    SHOW ERRORS PROCEDURE proc_name;    //存储过程
    SHOW ERRORS FUNCTION my_func;        //函数
    SHOW ERRORS TRIGGER my_trig;        //触发器
    SHOW ERRORS PACKAGE my_pack        //包

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值