• 触发器


     

    范例: 只有在每个月的10日才允许办理新雇员入职与离职,其他时间不允许增加新雇员数据

    CREATE OR REPLACE TRIGGER forbid_emp_trigger

    BEFORE INSERT OR DELETE

    ON emp

    DECLARE

    v_currentdate VARCHAR(20) ;

    BEGIN

    SELECT TO_CHAR(SYSDATE,'dd') INTO v_currentdate FROM dual ;

    IF TRIM(v_currentdate)!='10' THEN

    RAISE_APPLICATION_ERROR(-20008,'在每月的10号才允许办理入职手续!') ;

    END IF ;

    END ;

    /

    范例:emp表之中增加新雇员信息,当前不是当月10

    INSERT INTO emp (empno,ename,job,hiredate,sal,comm,mgr,deptno)

    VALUES (8998,'MLDN','MANAGER',SYSDATE,2000,500,7369,40) ;

     

    范例:在星期一、周末以及每天下班时间(每天9:00以前、18:00以后)后不允许更新emp数据表

    CREATE OR REPLACE TRIGGER forbid_emp_trigger

    BEFORE INSERT OR DELETE OR UPDATE

    ON emp

    DECLARE

    v_currentweak VARCHAR(20) ;

    v_currenthour VARCHAR(20) ;

    BEGIN

    SELECT TO_CHAR(SYSDATE,'day'),TO_CHAR(SYSDATE,'hh24') INTO v_currentweak, v_currenthour FROM dual ;

    IF TRIM(v_currentweak)='星期一' OR TRIM(v_currentweak)='星期六' OR TRIM(v_currentweak)='星期日' THEN

    RAISE_APPLICATION_ERROR(-20008,'在周末及周一不允许更新emp数据表!') ;

    ELSIF TRIM(v_currenthour)<'9' OR TRIM(v_currenthour)>'18' THEN

    RAISE_APPLICATION_ERROR(-20009,'在下班时间不能够修改emp表数据!') ;

    END IF ;

    END ;

    /

    范例:假设当前日期时间为周日,发出以下增加数据操作

    INSERT INTO emp (empno,ename,job,hiredate,sal,comm,mgr,deptno)

    VALUES (8998,'MLDN','MANAGER',SYSDATE,2000,500,7369,40) ;

     

    范例:在每天12点以后,不允许修改雇员工资和佣金

    CREATE OR REPLACE TRIGGER forbid_emp_trigger

    BEFORE UPDATE OF sal,comm

    ON emp

    DECLARE

    v_currenthour VARCHAR(20) ;

    BEGIN

    SELECT TO_CHAR(SYSDATE,'hh24') INTO v_currenthour FROM dual ;

    IF TRIM(v_currenthour)>'12' THEN

    RAISE_APPLICATION_ERROR(-20009,'每天12点以后不允许更新雇员工资、佣金。') ;

    END IF ;

    END ;

    /

    范例:当前时间已超过中午12点,更新emp表中的salcomm字段

    UPDATE emp SET sal=9000,comm=5000 WHERE empno=7369 ;

     

    范例:每一位雇员都要根据其收入上缴所得税,假设所得税的上缴原则为:2000以下上缴3%2000 ~ 5000上缴8%5000以上上缴10%,现在要求建立一张新的数据表,可以记录出雇员的编号、姓名、工资、佣金、上缴所得税数据,并且在每次修改雇员表中salcomm字段后可以自动更新记录。

    DROP TABLE emp_tax PURGE ;

    CREATE TABLE emp_tax (

    empno NUMBER(4) ,

    ename VARCHAR2(10) ,

    sal NUMBER(7,2) ,

    comm NUMBER(7,2) ,

    tax NUMBER(7,2) ,

    CONSTRAINT pk_empno PRIMARY KEY (empno) ,

    CONSTRAINT fk_empno FOREIGN KEY (empno) REFERENCES emp(empno) ON DELETE CASCADE

    ) ;

    CREATE OR REPLACE TRIGGER forbid_emp_trigger

    AFTER UPDATE OR INSERT OF ename , sal , comm

    ON emp

    DECLARE

    PRAGMA AUTONOMOUS_TRANSACTION ; -- 触发器自治事务

    CURSOR cur_emp IS SELECT * FROM emp ; -- 定义游标,找到每行纪录

    v_empRow emp%ROWTYPE ; -- 保存emp的每行纪录

    v_salary emp.sal%TYPE ; -- 计算总收入

    v_empTax emp_tax.tax%TYPE ; -- 保存税收的数值

    BEGIN

    DELETE FROM emp_tax ; -- 清空emp_tax表的纪录

    FOR v_empRow IN cur_emp LOOP

    v_salary := v_empRow.sal + NVL(v_empRow.comm , 0) ; -- 计算总工资

    IF v_salary < 2000 THEN

    v_empTax := v_salary * 0.03 ; -- 上缴3%的税

    ELSIF v_salary BETWEEN 2000 AND 5000 THEN

    v_empTax := v_salary * 0.08 ; -- 上缴8%的税

    ELSIF v_salary > 5000 THEN

    v_empTax := v_salary * 0.1 ; -- 上缴10%的税

    END IF ;

    INSERT INTO emp_tax(empno,ename,sal,comm,tax) VALUES

    (v_empRow.empno , v_empRow.ename , v_empRow.sal , v_empRow.comm , v_empTax) ;

    END LOOP ;

    COMMIT ; -- 提交事务

    END ;

    /

    范例:emp表中增加一条新的记录,而后查询emp_tax表记录

    INSERT INTO emp (empno,ename,job,hiredate,sal,comm,mgr,deptno)

    VALUES (9898,'MLDN','MANAGER',SYSDATE,2000,500,7369,40) ;

    范例:增加完成后查询emp_tax表记录

    SELECT * FROM emp_tax ;

     

    范例:增加雇员信息时,其职位必须在已有职位之内选择,并且工资不能超过5000

    CREATE OR REPLACE TRIGGER forbid_emp_trigger

    BEFORE INSERT

    ON EMP

    FOR EACH ROW

    DECLARE

    v_jobCount NUMBER ;

    BEGIN

    SELECT COUNT(empno) INTO v_jobCount FROM emp WHERE :new.job IN (

    SELECT DISTINCT job FROM emp) ;

    IF v_jobCount = 0 THEN -- 没有此职位信息

    RAISE_APPLICATION_ERROR(-20008,'增加雇员的职位信息名称错误!') ;

    ELSE

    IF :new.sal > 5000 THEN

    RAISE_APPLICATION_ERROR(-20008,'增加雇员的工资不得超过5000') ;

    END IF ;

    END IF ;

    END ;

    /

    范例:插入错误的数据

    INSERT INTO emp (empno,ename,job,hiredate,sal,comm,mgr,deptno)

    VALUES (8998,'MLDN','经理',SYSDATE,9000,500,7369,40) ;

     

    范例:修改emp表的基本工资涨幅不能超过10%

    CREATE OR REPLACE TRIGGER emp_update_trigger

    BEFORE UPDATE OF sal

    ON emp

    FOR EACH ROW

    BEGIN

    IF ABS((:new.sal-:old.sal)/:old.sal) > 0.1 THEN

    RAISE_APPLICATION_ERROR(-20008,'雇员工资修改幅度太大!') ;

    END IF ;

    END;

    /

    范例:将雇员编号是7369的雇员工资增长为5000

    UPDATE emp SET sal=5000 WHERE empno=7369 ;

     

    范例:不能删除所有10部门的雇员

    CREATE OR REPLACE TRIGGER emp_delete_trigger

    BEFORE DELETE

    ON emp

    FOR EACH ROW

    BEGIN

    IF :old.deptno=10 THEN

    RAISE_APPLICATION_ERROR(-20008,:old.empno || '10部门雇员,无法删除此部门雇员!') ;

    END IF ;

    END;

    /

    范例:删除雇员编号是7839的雇员信息(此雇员在10部门)

    DELETE FROM emp WHERE empno=7839 ;

     

    范例:错误的使用标识符:new”和“:old

    CREATE OR REPLACE TRIGGER emp_error_trigger

    BEFORE UPDATE

    ON emp

    FOR EACH ROW

    DECLARE

    v_empRow emp%ROWTYPE ;

    BEGIN

    v_empRow := :old ; -- 错误

    END;

    /

     

    范例:错误的程序 —— 在触发器之中无法修改old数据

    CREATE OR REPLACE TRIGGER emp_update_old_trigger

    BEFORE UPDATE OF sal

    ON emp

    FOR EACH ROW

    BEGIN

    :old.sal := 100 ;  -- 错误,无法修改old数据

    END;

    /

     

    范例:数据库创建脚本

    DROP SEQUENCE member_sequence ;

    DROP TABLE member PURGE ;

    DROP TABLE membertemp PURGE ;

    CREATE SEQUENCE member_sequence ;

    CREATE TABLE member(

    mid NUMBER ,

    name VARCHAR2(30) ,

    address VARCHAR2(50) ,

    CONSTRAINT pk_mid PRIMARY KEY(mid)

    ) ;

    CREATE TABLE membertemp AS SELECT * FROM member WHERE 1=2 ;

    范例:在触发器之中修改new数据

    CREATE OR REPLACE TRIGGER member_insert_trigger

    BEFORE INSERT

    ON membertemp  

    FOR EACH ROW

    BEGIN

    DELETE FROM membertemp ;

    INSERT INTO member(mid,name,address) VALUES (member_sequence.NEXTVAL,:new.name ,:new.address ) ;

    END;

    /

     

    范例:membertemp表中执行增加数据操作

    INSERT INTO membertemp(name,address) VALUES ('李兴华','中国') ;

    INSERT INTO membertemp(name,address) VALUES ('董  楠','MLDN') ;

    COMMIT ;

     

    范例:查询member表数据

    SELECT * FROM member ;

     

    范例:换种方式实现本程序的触发器

    CREATE OR REPLACE TRIGGER member_insert_trigger

    BEFORE INSERT

    ON membertemp  

    FOR EACH ROW

    DECLARE

    v_memberRow member%ROWTYPE ;

    BEGIN

    DELETE FROM membertemp ;

    SELECT member_sequence.NEXTVAL INTO :new.mid FROM dual ;

    v_memberRow.mid := :new.mid ;

    v_memberRow.name := :new.name ;

    v_memberRow.address := :new.address ;

    INSERT INTO member VALUES v_memberRow ;

    END;

    /

     

    范例:通过REFERENCING子句设置别名(修改雇员工资涨副触发器)

    CREATE OR REPLACE TRIGGER emp_insert_trigger

    BEFORE UPDATE OF sal

    ON emp

    REFERENCING old AS emp_old new AS emp_new

    FOR EACH ROW

    BEGIN

    IF ABS((:emp_new.sal-:emp_old.sal)/:emp_old.sal) > 0.1 THEN

    RAISE_APPLICATION_ERROR(-20008,'雇员工资涨副太大!') ;

    END IF ;

    END;

    /

     

    范例:在增加雇员时,判断雇员工资是否存在,如果工资为0则报错

    CREATE OR REPLACE TRIGGER emp_insert_trigger

    BEFORE INSERT

    ON emp  

    FOR EACH ROW

    WHEN (new.sal = 0)

    BEGIN

    RAISE_APPLICATION_ERROR(-20008,:new.empno || '的工资为0,不符合工资规定!') ;

    END;

    /

    范例:增加新雇员,工资为0 —— 不符合操作要求

    INSERT INTO emp (empno,ename,job,hiredate,sal,comm,mgr,deptno)

    VALUES (8998,'MLDN','经理',SYSDATE,0,500,7369,40) ;

     

    范例:要求工资只能上涨,不能降低

    CREATE OR REPLACE TRIGGER emp_sal_update_trigger

    BEFORE UPDATE

    ON emp

    FOR EACH ROW

    WHEN (new.sal<old.sal)

    BEGIN

    RAISE_APPLICATION_ERROR(-20008,:old.empno || '的工资少于其原本工资,无法更新!') ;

    END;

    /

    范例:7369的工资修改为300(原本为800,现在修改为300,属于降低工资,满足触发条件)

    UPDATE emp SET sal=300 WHERE empno=7369 ;

     

    范例:定义DEPT_LOG

    DROP TABLE dept_log PURGE ;

    DROP SEQUENCE dept_log_seq ;

    CREATE SEQUENCE dept_log_seq ;

    CREATE TABLE dept_log (

    logid NUMBER ,

    type VARCHAR2(20) NOT NULL ,

    deptno NUMBER(2) ,

    logdate DATE ,

    dname VARCHAR2(14) NOT NULL ,

    loc VARCHAR2(13) NOT NULL ,

    CONSTRAINT pk_logid PRIMARY KEY (logid)

    ) ;

     

    范例:定义触发器,针对于不同的DML操作进行日志记录

    CREATE OR REPLACE TRIGGER dept_update_trigger

    BEFORE INSERT OR UPDATE OR DELETE

    ON dept

    FOR EACH ROW

    BEGIN

    IF INSERTING THEN

    INSERT INTO dept_log (logid,type,logdate,deptno,dname,loc)

    VALUES (dept_log_seq.nextval,'INSERT',SYSDATE,:new.deptno,:new.dname,:new.loc) ;

    ELSIF UPDATING THEN

    INSERT INTO dept_log (logid,type,logdate,deptno,dname,loc)

    VALUES (dept_log_seq.nextval,'UPDATE',SYSDATE,:new.deptno,:new.dname,:new.loc) ;

    ELSE -- 相当于DELETING

    INSERT INTO dept_log (logid,type,logdate,deptno,dname,loc)

    VALUES (dept_log_seq.nextval,'DELETE',SYSDATE,:old.deptno,:old.dname,:old.loc) ;

    END IF ;

    END;

    /

     

    范例:dept表中执行一些DML操作

    INSERT INTO dept(deptno,dname,loc) VALUES (50,'MLDN','北京') ;

    INSERT INTO dept(deptno,dname,loc) VALUES (60,'教学部','天津') ;

    UPDATE dept SET dname='北京' WHERE deptno=60 ;

    UPDATE dept SET dname='MLDNJAVA' WHERE deptno=50 ;

    DELETE FROM dept WHERE deptno=60 ;

    COMMIT ;

    范例:查询dept_log数据表

    SELECT * FROM dept_log ;

     

    范例:定义三个针对于增加操作的触发器

    CREATE OR REPLACE TRIGGER emp_insert_one

    BEFORE INSERT

    ON emp

    FOR EACH ROW

    BEGIN

    DBMS_OUTPUT.put_line('执行第1个触发器(emp_insert_one') ;

    END ;

    /

    CREATE OR REPLACE TRIGGER emp_insert_two

    BEFORE INSERT

    ON emp

    FOR EACH ROW

    BEGIN

    DBMS_OUTPUT.put_line('执行第2个触发器(emp_insert_two') ;

    END ;

    /

    CREATE OR REPLACE TRIGGER emp_insert_three

    BEFORE INSERT

    ON emp

    FOR EACH ROW

    BEGIN

    DBMS_OUTPUT.put_line('执行第3个触发器(emp_insert_three') ;

    END ;

    /

    范例:编写增加数据操作

    INSERT INTO emp (empno,ename,job,hiredate,sal,comm,mgr,deptno)

    VALUES (8998,'MLDN','经理',SYSDATE,0,500,7369,40) ;

     

    范例:修改触发器创建语法

    CREATE OR REPLACE TRIGGER emp_insert_one

    BEFORE INSERT

    ON emp

    FOR EACH ROW

    BEGIN

    DBMS_OUTPUT.put_line('执行第1个触发器(emp_insert_one') ;

    END ;

    /

    CREATE OR REPLACE TRIGGER emp_insert_two

    BEFORE INSERT

    ON emp

    FOR EACH ROW

    FOLLOWS emp_insert_one

    BEGIN

    DBMS_OUTPUT.put_line('执行第2个触发器(emp_insert_two') ;

    END ;

    /

    CREATE OR REPLACE TRIGGER emp_insert_three

    BEFORE INSERT

    ON emp

    FOR EACH ROW

    FOLLOWS emp_insert_two

    BEGIN

    DBMS_OUTPUT.put_line('执行第3个触发器(emp_insert_three') ;

    END ;

    /

    范例:定义一张数据表

    DROP TABLE info PURGE ;

    CREATE TABLE info(

    id NUMBER ,

    title VARCHAR2(50)

    ) ;

    INSERT INTO info (id,title) VALUES (1,'www.mldnjava.cn') ; 

     

    范例:info表增加一个触发器

    CREATE OR REPLACE TRIGGER info_trigger

    BEFORE INSERT OR UPDATE OR DELETE

    ON info

    FOR EACH ROW

    DECLARE

    v_infocount NUMBER ;

    BEGIN

    SELECT COUNT(id) INTO v_infocount FROM info ;

    END ;

    /

    范例:执行更新操作

    UPDATE info SET id=2 ;

     

    范例:验证复合触发器

    CREATE OR REPLACE TRIGGER compound_trigger

    FOR INSERT OR UPDATE OR DELETE ON dept

    COMPOUND TRIGGER

    BEFORE STATEMENT IS-- 语句执行前触发(表级)

    BEGIN

    DBMS_OUTPUT.put_line('1BEFORE STATEMENT .') ;

    END BEFORE STATEMENT ;

    BEFORE EACH ROW IS-- 语句执行前触发(行级)

    BEGIN

    DBMS_OUTPUT.put_line('2BEFORE EACH ROW .') ;

    END BEFORE EACH ROW ;

    AFTER STATEMENT IS-- 语句执行后触发(表级)

    BEGIN

    DBMS_OUTPUT.put_line('3AFTER STATEMENT .') ;

    END AFTER STATEMENT ;

    AFTER EACH ROW IS-- 语句执行后触发(行级)

    BEGIN

    DBMS_OUTPUT.put_line('4AFTER EACH ROW .') ;

    END AFTER EACH ROW ;

    END ;

    /

    范例:dept表中增加一条新数据

    INSERT INTO dept(deptno,dname,loc) VALUES (99,'MLDNJAVA','北京') ;

     

    范例:定义复合触发器

    CREATE OR REPLACE TRIGGER compound_trigger

    FOR INSERT OR UPDATE OR DELETE ON dept

    COMPOUND TRIGGER

    BEFORE EACH ROW IS -- 语句执行前触发(行级)

    BEGIN

    IF INSERTING THEN

    IF :new.dname IS NULL THEN

    :new.dname := 'MLDNJAVA' ;

    END IF ;

    IF :new.loc IS NULL THEN

    :new.loc := '中国' ;

    END IF ;

    END IF ;

    END BEFORE EACH ROW ;

    END ;

    /

     

    范例:增加一条部门信息

    INSERT INTO dept(deptno) VALUES (99) ;

    COMMIT ;

    范例:查询更新后的dept表记录

    SELECT * FROM dept ;

     

    范例:定义触发器

    CREATE OR REPLACE TRIGGER emp_compound_trigger

    FOR INSERT OR UPDATE OR DELETE ON emp

    COMPOUND TRIGGER

    BEFORE STATEMENT IS -- 周末不允许更新

    v_currentweak VARCHAR2(20) ;

    BEGIN

    SELECT TO_CHAR(SYSDATE,'day') INTO v_currentweak FROM dual ;

    IF TRIM(v_currentweak) IN ('星期六' , '星期日') THEN

    RAISE_APPLICATION_ERROR(-20008,'在周末不允许更新emp数据表!') ;

    END IF ;

    END BEFORE STATEMENT ;

    BEFORE EACH ROW IS

    v_avgSal emp.sal%TYPE ;

    BEGIN

    IF INSERTING OR UPDATING THEN

    :new.ename := UPPER(:new.ename) ;

    :new.job := UPPER(:new.job) ;

    END IF ;

    IF INSERTING THEN

    SELECT AVG(sal) INTO v_avgSal FROM emp ;

    IF :new.sal > v_avgSal THEN

    RAISE_APPLICATION_ERROR(-20009,'新进雇员工资不得高于公司平均工资!') ;

    END IF ;

    END IF ;

    END BEFORE EACH ROW ;

    END ;

    /

    范例:向雇员表中增加一条正确的数据

    INSERT INTO emp (empno,ename,job,mgr,sal,comm,deptno,hiredate)

    VALUES (9999,'mldn','manager',7566,1680,null,20,SYSDATE) ;

    COMMIT ;

     

    范例:查询emp表中9999雇员信息

    SELECT * FROM emp WHERE empno=9999 ;

     

    范例:向雇员表增加一条雇员信息,工资为5000(已经超过了平均工资)

    INSERT INTO emp (empno,ename,job,mgr,sal,comm,deptno,hiredate)

    VALUES (8888,'lixinghua','manager',7566,5000,null,20,SYSDATE) ;

    范例:创建一张包含20部门雇员编号、姓名、职位、基本工资、部门编号、部门名称、位置的视图

    CREATE OR REPLACE VIEW v_myview AS

    SELECT e.empno , e.ename , e.job , e.sal , d.deptno , d.dname , d.loc

    FROM emp e,dept d

    WHERE e.deptno=d.deptno AND d.deptno=20 ;

     

    范例:向视图插入一条数据

    INSERT INTO v_myview (empno , ename, job , sal , deptno,dname,loc)

    VALUES (6688, '魔乐' , 'CLERK' , 2000, 50 , '教学' , '北京') ;

     

    范例:创建一个INSERT替代触发器,用于执行视图更新操作

    CREATE OR REPLACE TRIGGER view_trigger

    INSTEAD OF INSERT ON v_myview

    FOR EACH ROW

    DECLARE

    v_empCount NUMBER ;

    v_deptCount NUMBER ;

    BEGIN

    -- 判断要增加的雇员是否存在

    SELECT COUNT(empno) INTO v_empCount FROM emp WHERE empno=:new.empno ;

    -- 判断要增加的部门是否存在

    SELECT COUNT(deptno) INTO v_deptCount FROM dept WHERE deptno=:new.deptno ;

    IF v_deptCount = 0 THEN -- 部门不存在

    INSERT INTO dept(deptno,dname,loc) VALUES (:new.deptno , :new.dname , :new.loc) ;

    END IF ;

    IF v_empCount = 0 THEN

    INSERT INTO emp(empno,ename,job,sal,deptno)

    VALUES (:new.empno , :new.ename , :new.job , :new.sal , :new.deptno) ;

    END IF ;

    END ;

    /

    范例:执行视图增加操作

    INSERT INTO v_myview (empno , ename, job , sal , deptno,dname,loc)

    VALUES (6688, '魔乐' , 'CLERK' , 2000, 50 , '教学' , '北京') ;

    COMMIT ;

    范例:查询emp表中是否存在了新增的6688记录

    SELECT * FROM emp WHERE empno=6688 ;

     

    范例:查询dept表中是否存在了新增的50部门记录

    SELECT * FROM dept WHERE deptno=50 ;

     

    范例:创建一个UPDATE替代触发器

    CREATE OR REPLACE TRIGGER view_trigger

    INSTEAD OF UPDATE ON v_myview

    FOR EACH ROW

    BEGIN

    UPDATE emp SET ename=:new.empno , job=:new.job , sal=:new.sal WHERE empno=:new.empno ;

    UPDATE dept SET dname=:new.dname,loc=:new.loc WHERE deptno=:new.deptno ;

    END ;

    /

     

    范例:更新视图信息

    UPDATE v_myview SET ename='史密思',sal=2000,dname='调研部' WHERE empno=7369 ;

    COMMIT ;

     

    范例:查询v_myview视图

    SELECT * FROM v_myview ;

     

    范例:查询emp表中7369雇员信息是否被更新

    SELECT * FROM emp WHERE empno=7369 ;

     

    范例:查询dept表中20部门的信息是否被更新

    SELECT * FROM dept WHERE deptno=20 ;

     

    范例:创建一个DELETE替代触发器

    CREATE OR REPLACE TRIGGER view_trigger

    INSTEAD OF DELETE ON v_myview

    FOR EACH ROW

    DECLARE

    v_empCount NUMBER ;

    BEGIN

    DELETE FROM emp WHERE empno=:old.empno ;

    SELECT COUNT(empno) INTO v_empCount FROM emp WHERE deptno=:old.deptno ;

    IF v_empCount = 0 THEN -- 此部门没有雇员

    DELETE FROM dept WHERE deptno=:old.deptno ;

    END IF ;

    END ;

    /

    范例:删除视图之中所有20部门的雇员

    DELETE FROM v_myview WHERE deptno=20 ;

    COMMIT ;

     

    范例:将三个不同功能的替代触发器变为一个替代触发器

    CREATE OR REPLACE TRIGGER view_trigger

    INSTEAD OF INSERT OR UPDATE OR DELETE ON v_myview

    FOR EACH ROW

    DECLARE

    v_empCount NUMBER ;

    v_deptCount NUMBER ;

    BEGIN

    IF INSERTING THEN

    -- 判断要增加的雇员是否存在

    SELECT COUNT(empno) INTO v_empCount FROM emp WHERE empno=:new.empno ;

    -- 判断要增加的部门是否存在

    SELECT COUNT(deptno) INTO v_deptCount FROM dept WHERE deptno=:new.deptno ;

    IF v_deptCount = 0 THEN -- 部门不存在

    INSERT INTO dept(deptno,dname,loc)

    VALUES (:new.deptno , :new.dname , :new.loc) ;

    END IF ;

    IF v_empCount = 0 THEN

    INSERT INTO emp(empno,ename,job,sal,deptno)

    VALUES (:new.empno , :new.ename , :new.job , :new.sal , :new.deptno) ;

    END IF ;

    ELSIF UPDATING THEN

    UPDATE emp SET ename=:new.empno , job=:new.job , sal=:new.sal WHERE empno=:new.empno ;

    UPDATE dept SET dname=:new.dname,loc=:new.loc WHERE deptno=:new.deptno ;

    ELSIF DELETING THEN

    DELETE FROM emp WHERE empno=:old.empno ;

    SELECT COUNT(empno) INTO v_empCount FROM emp WHERE deptno=:old.deptno ;

    IF v_empCount = 0 THEN -- 此部门没有雇员

    DELETE FROM dept WHERE deptno=:old.deptno ;

    END IF ;

    ELSE

    NULL ;

    END IF ;

    END ;

    /

     

    范例:定义嵌套表

    -- 1、定义复合类型

    DROP TYPE project_nested ;

    DROP TYPE project_type ;

    CREATE OR REPLACE TYPE project_type AS OBJECT(

    projectid NUMBER ,

    projectname VARCHAR2(50) ,

    projectfunds NUMBER ,

    pubdate DATE

    ) ;

    /

    -- 2、定义嵌套表类型

    CREATE OR REPLACE TYPE project_nested AS TABLE OF project_type NOT NULL ;

    /

    -- 3、创建嵌套表类型的数据表

    DROP TABLE department PURGE ;

    CREATE TABLE department (

    did NUMBER ,

    deptname VARCHAR2(50) NOT NULL ,

    projects project_nested ,

    CONSTRAINT pk_did PRIMARY KEY(did)

    ) NESTED TABLE projects STORE AS projects_nsted_table ;

    -- 4、增加测试数据

    INSERT INTO department(did,deptname,projects) VALUES (10,'魔乐科技' ,

    project_nested(

    project_type(1,'Java实战开发' , 8900 , TO_DATE('2004-09-27','yyyy-mm-dd')),

    project_type(2,'Android实战开发' , 13900 ,TO_DATE('2010-07-19','yyyy-mm-dd'))

    )) ;

    INSERT INTO department(did,deptname,projects) VALUES (20,'MLDN出版部' ,

    project_nested(

    project_type(10,'Java开发实战经典》' , 79.8 , TO_DATE('2008-08-13','yyyy-mm-dd')) ,

    project_type(11,'Java Web开发实战经典》' , 69.8 , TO_DATE('2010-08-27','yyyy-mm-dd')) ,

    project_type(12,'Android开发实战经典》', 88 , TO_DATE('2012-03-19','yyyy-mm-dd'))

    )) ;

    COMMIT ;

    范例:创建一张只包含10部门信息的视图,在此视图之中存在嵌套表类型projects列。

    CREATE OR REPLACE VIEW v_department10

    AS

    SELECT did,deptname,projects

    FROM department

    WHERE did=10 ;

     

    范例:查看视图中的嵌套表数据

    SELECT * FROM TABLE (SELECT projects FROM v_department10) ;

     

    范例:对视图中的嵌套表执行增加数据操作 —— 错误

    INSERT INTO TABLE (SELECT projects FROM v_department10)

    VALUES (3,'Java高端人才培养',8000,TO_DATE('2013-09-19','yyyy-mm-dd')) ;

     

    范例:对视图中的嵌套表执行修改数据操作 —— 错误

    UPDATE TABLE (SELECT projects FROM v_department10) pro

    SET VALUE(pro) = project_type(2,'Android高级应用',3000,TO_DATE('2013-06-06','yyyy-mm-dd'))

    WHERE pro.projectid=2 ;

     

    范例:对视图中的嵌套表执行删除数据操作 —— 错误

    DELETE FROM TABLE(

    SELECT projects FROM v_department10) pro

    WHERE pro.projectid=2 ;

    范例:定义替代触发器实现对视图中的嵌套表数据更新

    CREATE OR REPLACE TRIGGER nested_trigger

    INSTEAD OF INSERT OR UPDATE OR DELETE

    ON NESTED TABLE projects OF v_department10

    DECLARE

    BEGIN

    IF INSERTING THEN

    INSERT INTO TABLE (SELECT projects FROM department WHERE did=:parent.did)

    VALUES (:new.projectid,:new.projectname,:new.projectfunds,:new.pubdate) ;

    ELSIF UPDATING THEN

    UPDATE TABLE (SELECT projects FROM department WHERE did=:parent.did) pro

    SET VALUE(pro) = project_type(:new.projectid,:new.projectname,:new.projectfunds,:new.pubdate)

    WHERE pro.projectid=:old.projectid ;

    ELSIF DELETING THEN

    DELETE FROM TABLE(

    SELECT projects FROM department WHERE did=:parent.did) pro

    WHERE pro.projectid=:old.projectid ;

    END IF ;

    END ;

    /

     

    范例:禁止c##scott用户的所有DDL操作

    CREATE OR REPLACE TRIGGER scott_forbid_trigger

    BEFORE DDL

    ON SCHEMA

    BEGIN

    RAISE_APPLICATION_ERROR(-20007,'scott用户禁止使用任何的DDL操作!') ;

    END ;

    /

     

    范例:创建一个序列

    CREATE SEQUENCE mldn_seq ;

    范例:数据库对象操作日志记录表创建脚本

    DROP TABLE object_log PURGE ;

    DROP SEQUENCE object_log_seq ;

    CREATE SEQUENCE object_log_seq ;

    CREATE TABLE object_log (

    oid NUMBER CONSTRAINT pk_oid PRIMARY KEY,

    username VARCHAR2(50) NOT NULL ,

    operatedate DATE NOT NULL ,

    objecttype VARCHAR2(50) NOT NULL ,

    objectowner VARCHAR2(50) NOT NULL

    ) ;

    范例:编写触发器实现对数据库对象操作的日志记录

    CREATE OR REPLACE TRIGGER object_trigger

    AFTER CREATE OR DROP OR ALTER

    ON DATABASE

    DECLARE

    BEGIN

    INSERT INTO c##scott.object_log(oid,username,operatedate,objecttype,objectowner) VALUES

       (c##scott.object_log_seq.nextval,ORA_LOGIN_USER,

        SYSDATE,ORA_DICT_OBJ_TYPE,ORA_DICT_OBJ_OWNER) ;

    END ;

    /

    范例:禁止修改emp数据表的empno(主键)列和deptno(外键)列的定义结构

    SELECT * FROM all_tab_columns

    WHERE table_name='EMP' AND owner='C##SCOTT';

     

    范例:c##scott用户中定义参数游标

    CREATE OR REPLACE TRIGGER emp_alter_trigger

    BEFORE ALTER

    ON SCHEMA

    DECLARE

    -- 操作的所有者以及操作的表名称由外部传递

    CURSOR emp_column_cur(p_tableOwner all_tab_columns.owner%TYPE , p_tableName all_tab_columns.table_name%TYPE) IS

    SELECT column_name FROM all_tab_columns

    WHERE owner=p_tableOwner AND table_name=p_tableName ;

    BEGIN

    IF ORA_DICT_OBJ_TYPE = 'TABLE' THEN -- 如果操作的是数据表

    FOR empColumnRow IN emp_column_cur(ORA_DICT_OBJ_OWNER , ORA_DICT_OBJ_NAME) LOOP

    IF ORA_IS_ALTER_COLUMN(empColumnRow.column_name) THEN

    -- empno字段要被修改

    IF empColumnRow.column_name = 'EMPNO' THEN

    RAISE_APPLICATION_ERROR(-20007,'empno字段不允许修改!') ;

    END IF ;

    -- deptno字段要被修改

    IF empColumnRow.column_name = 'DEPTNO' THEN

    RAISE_APPLICATION_ERROR(-20008,'deptno字段不允许修改!') ;

    END IF ;

    END IF ;

    IF ORA_IS_DROP_COLUMN(empColumnRow.column_name) THEN

    -- empno字段要被删除

    IF empColumnRow.column_name = 'EMPNO' THEN

    RAISE_APPLICATION_ERROR(-20009,'empno字段不允许删除!') ;

    END IF ;

    -- deptno字段要被删除

    IF empColumnRow.column_name = 'DEPTNO' THEN

    RAISE_APPLICATION_ERROR(-20010,'deptno字段不允许删除!') ;

    END IF ;

    END IF ;

    END LOOP ;

    END IF ;

    END ;

    /

    范例:修改empno字段

    ALTER TABLE emp MODIFY (empno NUMBER(6)) ;

     

    范例:删除deptno字段

    ALTER TABLE emp DROP COLUMN deptno ;

     

    范例:编写user_log数据表创建脚本

    DROP SEQUENCE user_log_seq ;

    DROP TABLE user_log PURGE ;

    CREATE SEQUENCE user_log_seq ;

    CREATE TABLE user_log (

    logid NUMBER CONSTRAINT pk_logid PRIMARY KEY ,

    username VARCHAR2(50) NOT NULL ,

    logondate DATE ,

    logoffdate DATE ,

    ip VARCHAR2(20) ,

    logtype VARCHAR2(20)

    ) ;

     

    范例:监控用户登录触发器 —— logon_trigger

    CREATE OR REPLACE TRIGGER logon_trigger

    AFTER LOGON

    ON DATABASE

    BEGIN

    INSERT INTO user_log(logid,username,logondate,ip,logtype)

    VALUES (user_log_seq.nextval,ORA_LOGIN_USER,SYSDATE,ORA_CLIENT_IP_ADDRESS,'LOGON')  ;

    END ;

    /

     

    范例:监控用户注销触发器 —— logoff_trigger

    CREATE OR REPLACE TRIGGER logoff_trigger

    BEFORE LOGOFF

    ON DATABASE

    BEGIN

    INSERT INTO user_log(logid,username,logoffdate,ip,logtype)

    VALUES (user_log_seq.nextval,ORA_LOGIN_USER,SYSDATE,ORA_CLIENT_IP_ADDRESS,'LOGOFF')  ;

    END ;

    /

     

    范例:回到sys用户下,查询user_log数据表

    CONN sys/change_on_install AS SYSDBA ;

    SELECT * FROM user_log ;

     

    范例:定义数据库事件记录表

    DROP TABLE db_event_log PURGE ;

    DROP SEQUENCE db_event_log_seq ;

    CREATE SEQUENCE db_event_log_seq ;

    CREATE TABLE db_event_log (

    eventId NUMBER CONSTRAINT pk_eventid PRIMARY KEY ,

    eventType VARCHAR2(50) NOT NULL ,

    eventDate DATE NOT NULL ,

    eventUser VARCHAR2(50) NOT NULL

    ) ;

     

    范例:编写触发器 —— 启动之后触发

    CREATE OR REPLACE TRIGGER startup_trigger

    AFTER STARTUP

    ON DATABASE

    BEGIN

    INSERT INTO db_event_log(eventId,eventType,eventDate,eventUser)

    VALUES (db_event_log_seq.nextval,'STARTUP',SYSDATE,ORA_LOGIN_USER) ;

    COMMIT ;

    END ;

    /

     

    范例:编写触发器 —— 关闭之前触发

    CREATE OR REPLACE TRIGGER shutdown_trigger

    BEFORE SHUTDOWN

    ON DATABASE

    BEGIN

    INSERT INTO db_event_log(eventId,eventType,eventDate,eventUser)

    VALUES (db_event_log_seq.nextval,'SHUTDOWN',SYSDATE,ORA_LOGIN_USER) ;

    COMMIT ;

    END ;

    /

    范例:查询db_event_log数据表记录

    SHUTDOWN ABORT

    STARTUP

    SELECT * FROM db_event_log ;

     

    范例:创建一张记录错误信息的数据表 —— db_error

    DROP SEQUENCE db_error_seq ;

    DROP TABLE db_error PURGE ;

    CREATE SEQUENCE db_error_seq ;

    CREATE TABLE db_error (

    eid NUMBER CONSTRAINT pk_eid PRIMARY KEY ,

    username VARCHAR2(50) ,

    errorDate DATE ,

    dbname VARCHAR2(50) ,

    content CLOB

    ) ;

     

    范例:定义数据库错误触发器

    CREATE OR REPLACE TRIGGER error_trigger

    AFTER SERVERERROR ON DATABASE

    BEGIN

    INSERT INTO db_error(eid,username,errorDate,dbname,content)

    VALUES (db_error_seq.nextval,ORA_LOGIN_USER,SYSDATE,ORA_DATABASE_NAME,

    DBMS_UTILITY.format_error_stack) ;

    END ;

    /

    范例:使用c##scott用户登录,查看user_triggers数据字典

    SELECT trigger_name,status,trigger_type,status,table_name,triggering_event,trigger_body FROM user_triggers ;

     

    范例:emp_alter_trigger触发器修改为禁用状态

    ALTER TRIGGER emp_alter_trigger DISABLE ;

    范例:查询数据字典表,确定触发器状态

    SELECT trigger_name,status FROM user_triggers ;

     

    范例:禁用触发器代码结构

    CREATE OR REPLACE TRIGGER emp_update_trigger

    BEFORE INSERT OR UPDATE OR DELETE

    ON dept

    DISABLE

    FOR EACH ROW

    BEGIN

    NULL ;

    END;

    /

     

    范例:启用emp表的全部触发器

    ALTER TABLE emp ENABLE ALL TRIGGERS;

     

    范例:删除forbid_emp_trigger触发器

    DROP TRIGGER emp_alter_trigger ;

    范例:在每月10号允许办理新近人员入职,同时入职的新雇员工资不能够超过公司的平均工资

    CREATE OR REPLACE PROCEDURE emp_update_date_proc

    AS

    v_currentdate VARCHAR2(20) ;

    BEGIN

    SELECT TO_CHAR(SYSDATE,'dd') INTO v_currentdate FROM dual ;

    IF TRIM(v_currentdate)!='10' THEN

    RAISE_APPLICATION_ERROR(-20008,'在每月的10号才允许办理入职手续!') ;

    END IF ;

    END;

    /

    CREATE OR REPLACE FUNCTION emp_avg_sal

    RETURN NUMBER

    AS

    v_avg_salary emp.sal%TYPE ;

    BEGIN

    SELECT AVG(sal) INTO v_avg_salary FROM emp ;

    RETURN v_avg_salary ;

    END;

    /

    CREATE OR REPLACE TRIGGER forbid_emp_trigger

    BEFORE INSERT

    ON emp

    FOR EACH ROW

    BEGIN

    emp_update_date_proc ; -- 调用过程

    IF :new.sal>emp_avg_sal() THEN -- 调用函数

    RAISE_APPLICATION_ERROR(-20009,'新进雇员工资不得高于公司平均工资!') ;

    END IF ;

    END ;

    /

  • 相关阅读:
    本周总结
    本周总结
    本周总结
    本周总结
    性能分析(4)
    大型网站高性能架构
    第二天大数据清洗
    性能分析(2)
    六大质量属性——性能分析(1)
    java设计模式9-代理模式
  • 原文地址:https://www.cnblogs.com/doudouxiaoye/p/5804374.html
Copyright © 2020-2023  润新知