sql触发器使用教程和命名规范.docx

上传人:b****7 文档编号:23749206 上传时间:2023-05-20 格式:DOCX 页数:15 大小:23.42KB
下载 相关 举报
sql触发器使用教程和命名规范.docx_第1页
第1页 / 共15页
sql触发器使用教程和命名规范.docx_第2页
第2页 / 共15页
sql触发器使用教程和命名规范.docx_第3页
第3页 / 共15页
sql触发器使用教程和命名规范.docx_第4页
第4页 / 共15页
sql触发器使用教程和命名规范.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

sql触发器使用教程和命名规范.docx

《sql触发器使用教程和命名规范.docx》由会员分享,可在线阅读,更多相关《sql触发器使用教程和命名规范.docx(15页珍藏版)》请在冰豆网上搜索。

sql触发器使用教程和命名规范.docx

sql触发器使用教程和命名规范

SQL触发器使用教程和命名标准

1,触发器简介

触发器〔Trigger〕是数据库对象的一种,编码方式类似存储过程,与某张表〔Table〕相关联,当有DML语句对表进展操作时,可以引起触发器的执行,到达对插入记录一致性,正确性和标准性控制的目的。

在当年C/S时代盛行的时候,由于客户端直接连接数据库,能保证数据库一致性的只有数据库本身,此时主键〔PrimaryKey〕,外键〔ForeignKey〕,约束〔Constraint〕和触发器成为必要的控制机制。

而触发器的实现比较灵敏,可编程性强,自然成为了最流行的控制机制。

到了B/S时代,开展成4层架构,客户端不再能直接访问数据库,只有中间件才可以访问数据库。

要控制数据库的一致性,既可以在中间件里控制,也可以在数据库端控制。

很多的青睐Java的开发者,随之将数据库当成一个黑盒,把大多数的数据控制工作放在了Servlet中执行。

这样做,不需要理解太多的数据库知识,也减少了数据库编程的复杂性,但同时增加了Servlet编程的工作量。

从架构设计来看,中间件的功能是检查业务正确性和执行业务逻辑,假设把数据的一致性检查放到中间件去做,需要在所有涉及到数据写入的地方进展数据一致性检查。

由于数据库访问相对于中间件来说是远程调用,要编写统一的数据一致性检查代码并非易事,一般采用在多个地方的增加类似的检查步骤。

一旦一致性检查过程发生调整,势必导致多个地方的修改,不仅增加工作量,而且无法保证每个检查步骤的正确性。

触发器的应用,应该放在关键的,多方发起的,高频访问的数据表上,过多使用触发器,会增加数据库负担,降低数据库性能。

而放弃使用触发器,那么会导致系统架构设计上的问题,影响系统的稳定性。

2,触发器例如

触发器代码类似存储过程,以PL/SQL脚本编写。

下面是一个触发器的例如:

新建员工工资表salary

create table SALARY

  EMPLOYEE_ID NUMBER,--员工ID

 MONTH       VARCHAR2(6),--工资月份

 AMOUNT      NUMBER --工资金额

创立与salary关联的触发器salary_trg_rai

1  Createorreplacetriggersalary_trg_rai

2  Afterinsertonsalary

3  Foreachrow

4    declare

5  Begin

6    (‘员工ID:

’||:

);

7    (‘工资月份:

’||:

);

8    (‘工资:

’||:

);

9    (‘触发器已被执行’);

10  End;

翻开一个SQLWindow窗口〔使用PL/SQLDeveloper工具〕,或在sqlplus中输入:

Insertintosalary(employee_id,month,amount)values(1,‘200606’,10000);

执行后可以在sqlplus中,或在SQLWindow窗口的Output中见到

员工ID:

1

工资月份:

200606

工资:

10000

触发器已执行

在代码的第一行,定义了数据库对象的类型是trigger,定义触发器的名称是salary_trg_rai

第二行说明了这是一个after触发器,在DML操作施行之后执行。

紧接着的insert说明了这是一个针对insert操作的触发器,每个对该表进展的insert操作都会执行这个触发器。

第三行说明了这是一个针对行级的触发器,当插入的记录有n条时,在每一条插入操作时都会执行该触发器,总共执行n次。

Declare后面跟的是本地变量定义部分,假设没有本地变量定义,此部分可以为空

Begin和end括起来的代码,是触发器的执行部分,一般会对插入记录进展一致性检查,在本例中打印了插入的记录和“触发器已执行〞。

其中:

new对象表示了插入的记录,可以通过:

来引用记录的每个字段值

3,触发器语法和功能

触发器的语法如下

CREATEORREPLACETRIGGER trigger_name

ON table_name

[FOREACHROW]

WHEN(condition)

DECLARE

BEGIN

      --触发器代码

END;

Trigger_name是触发器的名称。

可以选择before或者after或insteadof。

Before表示在DML语句施行前执行触发器,而after表示在在dml语句施行之后执行触发器,insteadof触发器用在对视图的更新上。

可以选择一个或多个DML语句,假设选择多个,那么用or分开,如:

insertorupdate。

Table_name是触发器关联的表名。

[FOREACHROW]为可选项,假设注明了FOREACHROW,那么说明了该触发器是一个行级的触发器,DML语句处理每条记录都会执行触发器;否那么是一个语句级的触发器,每个DML语句触发一次。

WHEN后跟的condition是触发器的响应条件,只对行级触发器有效,当操作的记录满足condition时,触发器才被执行,否那么不执行。

Condition中可以通过new对象和old对象〔注意区别于前面的:

new和:

old,在代码中引用需要加上冒号〕来引用操作的记录。

触发器代码可以包括三种类型:

未涉及数据库事务代码,涉及关联表〔上文语法中的table_name〕数据库事务代码,涉及除关联表之外数据库事务代码。

其中第一种类型代码只对数据进展简单运算和判断,没有DML语句,这种类型代码可以在所有的触发器中执行。

第二种类型代码涉及到对关联表的数据操作,比方查询关联表的总记录数或者往关联表中插入一条记录,该类型代码只能在语句级触发器中使用,假设在行级触发器中使用,将会报ORA-04091错误。

第三种类型代码涉及到除关联表之外的数据库事务,这种代码可以在所有触发器中使用。

从触发器的功能上来看,可以分成3类:

●         重写列〔仅限于before触发器〕

●         采取行动〔任何触发器〕

●         回绝事务〔任何触发器〕

“重写列〞用于对表字段的校验,当插入值为空或者插入值不符合要求,那么触发器用缺省值或另外的值代替,在多数情况下与字段的default属性一样。

这种功能只能在行级before触发器中执行。

“采取行动〞针对当前事务的特点,对相关表进展操作,比方根据当前表插入的记录更新其他表,银行中的总帐和分户帐间的总分关系就可以通过这种触发器功能来维护。

“回绝事务〞用在对数据的合法性检验上,当更新的数据不满足表或系统的一致性要求,那么通过抛出异常的方式回绝事务,在其上层的代码可以捕获这个异常并进展相应操作。

下面将通过举例说明,在例子中将触发器主体的语法一一介绍,读者可以在例子中体会触发器的功能。

4,例一:

行级触发器之一

CREATE OR REPLACE TRIGGER salary_raiu

AFTER INSERT OR UPDATE OF amount ON salary

FOR EACH ROW

BEGIN

    IF inserting THEN

       (‘插入’);

    ELSIF updating THEN

(‘更新amount列’);

         ENDIF;

END;

以上是一个afterinsert和afterupdate的行级触发器。

在第二行中ofamountonsalary的意思是只有当amount列被更新时,update触发器才会有效。

所以,以下语句将不会执行触发器:

Updatesalarysetmonth=‘200601’wheremonth=‘200606’;

在触发器主体的if语句表达式中,inserting,updating和deleting可以用来区分当前是在做哪一种DML操作,可以作为把多个类似触发器合并在一个触发器中判别触发事件的属性。

5,例二:

行级触发器之二

新建员工表employment

CREATE TABLE EMPLOYMENT

 EMPLOYEE_ID NUMBER,--员工ID

 MAXSALARY   NUMBER --工资上限

插入两条记录

Insertintoemploymentvalues(1,1000);

Insertintoemploymentvalues(2,2000);

CREATE OR REPLACE TRIGGER salary_raiu

AFTER INSERT OR UPDATE OF amount ON salary

FOR EACH ROW

WHEN ( NEW.amount>= 1000 AND (old.amount IS NULL OR OLD.amount<= 500))

DECLARE

   v_maxsalary NUMBER;

BEGIN

    SELECT maxsalary

        INTO v_maxsalary

        FROM employment

    WHERE employee_id=:

NEW.employee_id;

    IF :

NEW.amount>v_maxsalary THEN

       raise_application_error(-20000, '工资超限');

    END IF;

END;

以上的例子引入了一个新的表employment,表中的maxsalary字段代表该员工每月所能分配的最高工资。

下面的触发器根据插入或修改记录的employee_id,在employment表中查到该员工的每月最高工资,假设插入或修改后的amount超过这个值,那么报错误。

代码中的when子句说明了该触发器只针对修改或插入后的amount值超过1000,而修改前的amount值小于500的记录。

New对象和old对象分别表示了操作前和操作后的记录对象。

对于insert操作,由于当前操作记录无历史对象,所以old对象中所有属性是null;对于delete操作,由于当前操作记录没有更新对象,所以new对象中所有属性也是null。

但在这两种情况下,并不影响old和new对象的引用和在触发器主体中的使用,和普通的空值作同样的处理。

在触发器主体中,先通过:

,得到该员工的工资上限,然后在if语句中判断更新后的员工工资是否超限,假设超限那么错误代码为-20000,错误信息为“工资超限〞的自定义错误。

其中的raise_application_error包含两个参数,前一个是自定义错误代码,后一个是自定义错误代码信息。

其中自定义错误代码必须小于或等于-20000。

执行完该语句后,一个异常被抛出,假设在上一层有exception子句,该异常将被捕获。

如下面代码:

DECLARE

   code NUMBER;

   msg VARCHAR2(500);

BEGIN

    INSERT INTO salary(employee_id,amount) VALUES (2, 5000);

EXCEPTION

    WHEN OTHERS THEN

       code:

= SQLCODE;

       msg :

=substr(SQLERRM, 1, 500);

       (code);

       (msg);

END;

执行后,将在output中或者sqlplus窗口中见着以下信息:

-20000

ORA-20000:

 工资超出限制

ORA-06512:

 在"SCOTT.SALARY_RAI",line9

ORA-04088:

 触发器 'SCOTT.SALARY_RAI' 执行过程中出错

这里的raise_application_error相当于回绝了插入或者修改事务,当上层代码承受到这个异常后,判断该异常代码等于-20000,可以作出回滚事务或者继续其他事务的处理。

以上两个例子中用到的inserting,updating,deleting和raise_application_error都是dbms_standard包中的函数,详细的说明可以参照Oracle的帮助文档。

create or replace package  is

 procedure raise_application_error(num binary_integer,msg varchar2,

 function inserting return boolean;

 function deleting return boolean;

 function updating return boolean;

 function updating(colnam varchar2) return boolean;

end;

对于before和after行级触发器,:

new和:

old对象的属性值都是一样的,主要是对于在Oracle约束〔Constraint〕之前或之后的执行触发器的选择。

需要注意的是,可以在before行触发器中更改:

new对象中的值,但是在after行触发器就不行。

下面介绍一种insteadof触发器,该触发器主要使用在对视图的更新上,以下是insteadof触发器的语法:

CREATEORREPLACETRIGGER trigger_name

INSTEADOFON view_name

[FOREACHROW]

WHEN(condition)

DECLARE

BEGIN

      --触发器代码

END;

其他部分语法同前面所述的before和after语法是一样的,唯一不同的是在第二行用上了insteadof关键字。

对于普通的视图来说,进展insert等操作是被制止的,因为Oracle无法知道操作的字段详细是哪个表中的字段。

但我们可以通过建立insteadof触发器,在触发器主体中告诉Oracle应该更新,删除或者修改哪些表的哪部分字段。

如:

6,例三:

insteadof触发器

新建视图

CREATE VIEW employee_salary(employee_id,maxsalary, MONTH,amount) AS 

SELECT ,,b.MONTH,

FROM employmenta,salaryb

WHERE =

假设执行插入语句

INSERT INTO employee_salary(employee_id,maxsalary, MONTH,amount)

VALUES(10, 100000, '200606', 10000);

系统会报错:

ORA-01779:

无法修改与非键值保存表对应的列

我们可以通过建立以下的insteadof存储过程,将插入视图的值分别插入到两个表中:

create or replace trigger employee_salary_rii

 instead of insert on employee_salary 

 for each ROW

DECLARE

   v_cnt NUMBER;

BEGIN

 --检查是否存在该员工信息

    SELECT COUNT(*)

        INTO v_cnt

        FROM employment

    WHERE employee_id=:

NEW.employee_id;

    IF v_cnt= 0 THEN

        INSERT INTO employment

           (employee_id,maxsalary)

        VALUES

           (:

NEW.employee_id,:

NEW.maxsalary);

    END IF;

 --检查是否存在该员工的工资信息

    SELECT COUNT(*)

        INTO v_cnt

        FROM salary

    WHERE employee_id=:

NEW.employee_id

        AND MONTH =:

NEW.MONTH;

    IF v_cnt= 0 THEN

        INSERT INTO salary

           (employee_id, MONTH,amount)

        VALUES

           (:

NEW.employee_id,:

NEW.MONTH,:

NEW.amount);

    END IF;

END employee_salary_rii;

该触发器被建立后,执行上述insert操作,系统就会提示成功插入一条记录。

但需要注意的是,这里的“成功插入一条记录〞,只是Oracle并未发现触发器中有异常抛出,而根据insert语句中涉及的记录数作出一个判断。

假设触发器的主体什么都没有,只是一个空语句,Oracle也会报“成功插入一条记录〞。

同样道理,即使在触发器主体里往多个表中插入十条记录,Oracle的返回也是“成功插入一条记录〞。

行级触发器可以解决大部分的问题,但是假设需要对本表进展扫描检查,比方要检查总的工资是否超限了,用行级触发器是不行的,因为行级触发器主体中不能有涉及到关联表的事务,这时就需要用到语句级触发器。

以下是语句级触发器的语法:

CREATEORREPLACETRIGGER trigger_name

ON table_name

DECLARE

BEGIN

      --触发器主体

END;

从语法定义上来看,行级触发器少了foreachrow,也不能使用when子句来限定入口条件,其他部分都是一样的,包括insert,update,delete和insteadof都可以使用。

7,例四:

语句级触发器之一

CREATE OR REPLACE TRIGGER salary_saiu

AFTER INSERT OR UPDATE OF amount ON salary

DECLARE

   v_sumsalary NUMBER;

BEGIN

 SELECT SUM(amount) INTO v_sumsalary FROM salary;

    IF v_sumsalary> 500000 THEN

       raise_application_error(-20001, '总工资超过500000');

    END IF;

END;

以上代码定义了一个语句级触发器,该触发器检查在insert和update了amount字段后操作后,工资表中所有工资记录累加起来是否超过500000,假设超过那么抛出异常。

从这个例子可以看出,语句级触发器可以对关联表表进展扫描,扫描得到的结果可以用来作为判断一致性的标志。

需要注意的是,在before语句触发器主体和after语句触发器主体中对关联表进展扫描,结果是不一样的。

在before语句触发器主体中扫描,扫描结果将不包括新插入和更新的记录,也就是说当以上代码换成before触发器后,以下语句将不报错:

INSERT INTO salary(employee_id, month,amount) VALUEs(2, '200601', 600000)

这是因为在主体中得到的v_sumsalary并不包括新插入的600000工资。

另外,在语句级触发器中不能使用:

new和:

old对象,这一点和行级触发器是显著不同的。

假设需要检查插入或更新后的记录,可以采用临时表技术。

临时表是一种Oracle数据库对象,其特点是当创立数据的进程完毕后,进程所创立的数据也随之去除。

进程与进程不可以互相访问同一临时表中对方的数据,而且对临时表进展操作也不产生undo日志,减少了数据库的消耗。

详细有关临时表的知识,可以参看有关书籍。

为了在语句级触发器中访问新插入后修改后的记录,可以增加行级触发器,将更新的记录插入临时表中,然后在语句级触发器中扫描临时表,获得修改后的记录。

临时表的表构造一般与关联表的构造一致。

8,例五:

语句级触发器之二

目的:

限制每个员工的总工资不能超过50000,否那么停顿对该表操作。

创立临时表

create global temporary table SALARY_TMP

 EMPLOYEE_ID NUMBER,

 MONTH       VARCHAR2(6),

 AMOUNT      NUMBER

on commit delete rows;

为了把操作记录插入到临时表中,创立行级触发器:

CREATE OR REPLACE TRIGGER salary_raiu

AFTER INSERT OR UPDATE OF amount ON salary

FOR EACH ROW

BEGIN

 INSERT INTO salary_tmp(employee_id, month,amount)

 VALUES(:

NEW.employee_id,:

NEW.MONTH,:

NEW.amount);

END;

该触发器的作用是把更新后的记录信息插入到临时表中,假设更新了多条记录,那么每条记录都会保存在临时表中。

创立语句级触发器:

CREATE OR REPLACE TRIGGER salary_sai

AFTER INSERT OR UPDATE OF amount ON salary

DECLARE

   v_sumsalary NUMBER;

BEGIN

    FOR cur IN (SELECT * FROM salary_tmp) LOOP

        SELECT SUM(amount)

            INTO v_sumsalary

            FROM salary

        WHERE employee_id=;

        IF v_sumsalary> 50000 THEN

           raise_application_error(-20002, '员工累计工资超过50000');

        END IF;

    DELETE FROM salary_tmp;

    END LOOP;

END;

该触发器首先用游标从salary_tmp临时表中逐条读取更新或插入的记录,取employee_id,在关联表salary中查找所有一样员工的工资记录,并求和。

假设某员工工资总和超过50000,那么抛出异常。

假设检查通过,那么清空临时表,防止下次检查一样的记录。

执行以下语句:

INSERT INTO salary(employee

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 考试认证 > 从业资格考试

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1