签到成功

知道了

CNDBA社区CNDBA社区

DM 达梦 触发器 操作示例

2023-03-21 08:52 1961 0 原创 DM 达梦
作者: dave

详细说明直接参考官方手册,我们这里只看操作示例。

1 时间触发器

时间触发器是一种特殊的事件触发器。时间触发器的特点是用户可以定义在任何时间点、 时间区域、每隔多长时间等等的方式来激发触发器,而不是通过数据库中的某些操作包括DML、DDL 操作等来激发,它的最小时间精度为分钟。

时间触发器的创建语法如下:

CREATE [OR REPLACE] TRIGGER 触发器名 WITH ENCRYPTION 
AFTER TIMER ON DATABASE 
{时间定义语句} 
BEGIN 
执行语句 
END;
示例1:每个月的第 28 天,从早上 9 点开始到晚上 18 点之间,每隔一分钟就打印一个字符串―Hello World。
CREATE OR REPLACE TRIGGER timer1 
AFTER TIMER ON DATABASE 
FOR EACH 1 MONTH DAY 28 
FROM TIME '09:00' TO TIME '18:00' FOR EACH 1 MINUTE 
DECLARE 
str VARCHAR; 
BEGIN 
PRINT 'HELLO WORLD'; 
END; 
/
示例2:每隔一分钟输出一行―HELLO WORLD:
CREATE OR REPLACE TRIGGER timer2 
AFTER TIMER on database 
for each 1 day for each 1 minute 
BEGIN 
print 'HELLO WORLD'; 
END; 
/

2 表级触发器

2.1 表级触发器语法

CREATE [OR REPLACE] TRIGGER 触发器名[WITH ENCRYPTION] 
BEFORE|AFTER|INSTEAD OF 
DELETE|INSERT|UPDATE [OF 列名] 
ON 表名 
[FOR EACH ROW [WHEN 条件]] 
BEGIN 
DMSQL 程序语句 
END;

表级触发器的触发动作有三种:INSERT、DELETE 和 UPDATE 操作。其中 UPDATE 触发器会依赖于所修改的列,在定义中可通过 UPDATE OF <触发列清单>的形式来指定所修改的列,<触发列清单>指定的字段数不能超过 128 个。

触发级别:为行级(FOR EACH ROW)和语句级(FOR EACH STATEMENT )。例如将500行记录插入表TABLE_1中的 INSERT 语句,语句级 INSERT 触发器只执行一次。行级触发器会触发500次。FOR EACH STATEMENT 子句创建的,该子句可缺省。

所以表级触发器支持的类型有:https://www.cndba.cn/dave/article/116500

BEFORE INSERT: 在一个 INSERT 处理前激发一次 
AFTER INSERT:在一个 INSERT 处理后激发一次 
BEFORE DELETE:在一个 DELETE 处理前激发一次 
AFTER DELETE:在一个 DELETE 处理后激发一次 
BEFORE UPDATE:在一个 UPDATE 处理前激发一次 
AFTER UPDATE:在一个 UPDATE 处理后激发一次 

BEFORE INSERT FOR EACH ROW :每条新记录插入前激发 
AFTER INSERT FOR EACH ROW : 每条新记录插入后激发 
BEFORE DELETE FOR EACH ROW : 每条记录被删除前激发 
AFTER DELETE FOR EACH ROW : 每条记录被删除后激发 
BEFORE UPDATE FOR EACH ROW : 每条记录被修改前激发 
AFTER UPDATE FOR EACH ROW : 每条记录被修改后激发
2.2 示例 1 : BEFORE: 在插入一条记录前,将记录中 COL1 列的值加 1
SQL> create table t1(id int,name varchar(50));
操作已执行
已用时间: 23.943(毫秒). 执行号:8403.
SQL> CREATE OR REPLACE TRIGGER TRG_INS_BEFORE 
2   BEFORE INSERT ON SYSDBA.t1 
3   FOR EACH ROW 
4   BEGIN 
5   :NEW.ID:=:NEW.ID+1; 
6   END; 
7   /
操作已执行
已用时间: 24.357(毫秒). 执行号:8404.
SQL> insert into t1 values(1,'cndba');
影响行数 1

已用时间: 1.208(毫秒). 执行号:8405.
SQL> select * from t1;

行号     ID          NAME 
---------- ----------- -----
1          2           cndba

已用时间: 0.985(毫秒). 执行号:8406.
SQL>
2.3 示例2:AFTER: 在插入一条记录后,将插入的值以及操作类型记录到用于审计的表 T_TEMP 中。
SQL> CREATE TABLE T_TEMP(C1 INT,C2 CHAR(20)); 
操作已执行
已用时间: 11.429(毫秒). 执行号:8408.
SQL> CREATE OR REPLACE TRIGGER TRG_INS_AFTER 
2   AFTER INSERT ON SYSDBA.t1 
3   FOR EACH ROW 
4   BEGIN 
5   INSERT INTO SYSDBA.T_TEMP VALUES(:NEW.ID, 'INSERT ON T1'); 
6   END; 
7   /
操作已执行
已用时间: 14.753(毫秒). 执行号:8409.
SQL> insert into t1 values(1,'cndba');
影响行数 1

已用时间: 1.347(毫秒). 执行号:8410.
SQL> select * from t_temp;

行号     C1          C2                  
---------- ----------- --------------------
1          2           INSERT ON T1        

已用时间: 0.799(毫秒). 执行号:8411.
SQL>
2.4 示例3:INSTEAD OF 触发器

INSTEAD OF 只允许建立在视图上,并且只支持行级触发。 https://www.cndba.cn/dave/article/116500

当执行 UPDATE 动作时候,触发触发器。将原动作替换成触发器里的动作。

SQL> create view v1 as select * from SYSDBA.t1; 
操作已执行
已用时间: 18.211(毫秒). 执行号:8413.
SQL> CREATE OR REPLACE TRIGGER tri1 
2   INSTEAD OF UPDATE ON SYSDBA.v1
3   BEGIN 
4   insert into t1 values(100,'https://www.cndba.cn'); 
5   END; 
6   /
操作已执行
已用时间: 16.429(毫秒). 执行号:8414.
SQL> select * from v1;

行号     ID          NAME 
---------- ----------- -----
1          2           cndba
2          2           cndba

已用时间: 1.293(毫秒). 执行号:8415.
SQL> update v1 set id=100;   
影响行数 2

已用时间: 1.572(毫秒). 执行号:8416.
SQL> select * from v1;

行号     ID          NAME                
---------- ----------- --------------------
1          2           cndba
2          2           cndba
3          101         https://www.cndba.cn
4          101         https://www.cndba.cn

已用时间: 0.406(毫秒). 执行号:8417.
SQL> select * from t1;

行号     ID          NAME                
---------- ----------- --------------------
1          2           cndba
2          2           cndba
3          101         https://www.cndba.cn
4          101         https://www.cndba.cn

已用时间: 0.906(毫秒). 执行号:8418.
SQL>

由上面的查询结果可以看出。更新操作并没有成功,而是被触发器中的替换动作替换了。

2.5 示例4:引用变量(:NEW,:OLD) 使用

下例中触发器使用了:OLD 引用变量。该触发器是一个 UPDATE 前触发器,其目的是做更新操作时不论是否更新表中某列的值,该列的值保持原值不变。

SQL> create table t2 as select * from t1;
操作已执行
已用时间: 21.296(毫秒). 执行号:8419.
SQL> 

SQL> CREATE OR REPLACE TRIGGER trit2 
2   BEFORE UPDATE ON SYSDBA.t2 
3   FOR EACH ROW 
4   BEGIN 
5   :new.id:=:old.id; 
6   END; 
7   /
操作已执行
已用时间: 29.023(毫秒). 执行号:8420.
SQL>

当执行一个 UPDATE 语句时,触发器都将自动保持原来的ID值不变。

SQL> select * from t2;

行号     ID          NAME                
---------- ----------- --------------------
1          2           cndba
2          2           cndba
3          101         https://www.cndba.cn
4          101         https://www.cndba.cn

已用时间: 1.170(毫秒). 执行号:8421.
SQL> update t2 set id=999 where id=2;  
影响行数 2

已用时间: 1.438(毫秒). 执行号:8422.
SQL> select * from t2;

行号     ID          NAME                
---------- ----------- --------------------
1          2           cndba
2          2           cndba
3          101         https://www.cndba.cn
4          101         https://www.cndba.cn

已用时间: 0.422(毫秒). 执行号:8423.
SQL>

当然,可以改变原来的值,对数据进行处理,比如我们这里讲id 放大2倍再更新:

SQL> CREATE OR REPLACE TRIGGER trit2 
2   BEFORE UPDATE ON SYSDBA.t2 
3   FOR EACH ROW 
4   BEGIN 
5   :new.id:=:new.id*2; 
6   END; 
7   /
操作已执行
已用时间: 19.350(毫秒). 执行号:8424.
SQL> select * from t2;

行号     ID          NAME                
---------- ----------- --------------------
1          2           cndba
2          2           cndba
3          101         https://www.cndba.cn
4          101         https://www.cndba.cn

已用时间: 1.214(毫秒). 执行号:8425.

SQL> update t2 set id=100 where id=2;
影响行数 2

已用时间: 1.501(毫秒). 执行号:8426.
SQL> select * from t2;

行号     ID          NAME                
---------- ----------- --------------------
1          200         cndba
2          200         cndba
3          101         https://www.cndba.cn
4          101         https://www.cndba.cn

已用时间: 0.412(毫秒). 执行号:8427.
SQL>

上面没有指定列,也可以在update 指定具体列:

https://www.cndba.cn/dave/article/116500

SQL> CREATE OR REPLACE TRIGGER trit2 
2   BEFORE UPDATE of id,name ON SYSDBA.t2 
3   FOR EACH ROW 
4   BEGIN 
5   :new.id:=:old.id; 
6   END; 
7   /
操作已执行
已用时间: 11.697(毫秒). 执行号:8430.
SQL>
2.6 示例5:触发器谓词

触发事件可以是多个数据操作的组合,即一个触发器可能既是 INSERT 触发器,又DELETE 或 UPDATE 触发器。当一个触发器可以为多个 DML 语句触发时,在这种触发器体内部可以使用三个谓词:INSERTING、DELETING 和 UPDATING 来确定当前执行的是何种操作。https://www.cndba.cn/dave/article/116500

CREATE OR REPLACE TRIGGER LogChanges
AFTER INSERT OR DELETE OR UPDATE ON OTHER.READER 
FOR EACH ROW 
DECLARE 
v_ChangeType CHAR(1); 
BEGIN 
/* I‘表示 INSERT 操作,‘D‘表示 DELETE 操作,‘U‘表示 UPDATE 操作 */ 
IF INSERTING THEN 
v_ChangeType := 'I'; 
ELSIF UPDATING THEN 
v_ChangeType := 'U'; 
ELSE 
v_ChangeType := 'D'; 
END IF; 
/* 记录对 Reader 做的所有修改到表 ReaderAudit 中,包括修改人和修改时间 */ 
INSERT INTO OTHER.READERAUDIT 
VALUES 
(v_ChangeType, USER, SYSDATE, 
:old.reader_id, :old.name, :old.age, :old.gender, :old.major, 
:new.reader_id, :new.name, :new.age, :new.gender, :new.major); 
END; 
/

3 事件触发器

3.1 事件触发器说明

可以在数据库或模式上创建事件触发器。

  1. DDL 事件: 包括数据库和模式上的 DDL 操作;支持的DDL 事件包括:DDL 或 CREATE、ALTER、 DROP、GRANT、REVOKE、TRUNCATE、COMMENT等。

    https://www.cndba.cn/dave/article/116500

  2. 系统事件: 包括数据库上的除 DDL 操作以外系统事件;以上事件可以有多个,用 OR 列出。支持的系统事件包括:LOGIN/LOGON、LOGOUT/LOGOFF、SERERR、BACKUP DATABASE、 RESTORE DATABASE、AUDIT、NOAUDIT、TIMER、STARTUP、SHUTDOWN;

触发事件按照兼容性可以分为以下几个集合:{CREATE,ALTER,DROP,TRUNCATE,COMMENT }、{ GRANT, REVOKE }、{ LOGIN/LOGON, LOGOUT/LOGOFF }、{ SERERR }、{ BACKUP DATABASE, RESTORE DATABASE }、{AUDIT, NOAUDIT}、{TIMER}、{ STARTUP, SHUTDOWN }。

简单的说,同一个括号里的事件是相互冲突的,不能同时出现。

触发时间分为 BEFORE 和 AFTER:

  1. 所有 DDL 事件触发器都可以设置 BEFORE 或 AFTER 的触发时机,
  2. 系统事件中 LOGOUT 和 SHUTDOWN 仅能设置为 BEFORE,而其它则只能设置为 AFTER。

模式级触发器不能是 LOGIN/LOGON、LOGOUT/LOGOFF、SERERR、BACKUP DATABASE、RESTORE DATABASE、STARTUP 和 SHUTDOWN 事件触发器。

对于事件触发器,所有的事件信息都通过伪变量 :EVENTINFO 来取得。 不通操作变量值会有些出入,具体查看官方手册。

3.2 DDL 触发事件使用示例

创建基表:

SQL> CREATE TABLE T01_TRI_10000(OBJECTTYPE VARCHAR(500),OBJECTNAME VARCHAR(500), SCHEMANAME VARCHAR(500),DATABASENAME VARCHAR(500),OPUSER VARCHAR(500), OPTIME VARCHAR(500)); 
操作已执行
已用时间: 21.509(毫秒). 执行号:8431.
SQL> CREATE TABLE T02_TRI_10000 (C1 INT,C2 VARCHAR(50));
操作已执行
已用时间: 19.458(毫秒). 执行号:8432.
SQL> INSERT INTO T02_TRI_10000 VALUES (1,'https://www.cndba.cn'); 
影响行数 1
已用时间: 0.915(毫秒). 执行号:8433.

创建事件触发器:

SQL> CREATE TRIGGER TRI01_TRI_10000 
2   BEFORE CREATE ON DATABASE 
3   BEGIN 
4   INSERT INTO T01_TRI_10000 VALUES(:EVENTINFO.OBJECTTYPE,:EVENTINFO.OBJECTNAME,:EVENTINFO.SCHEMANAME,:EVENTINFO.DATABASENAME,:EVENTINFO.OPUSER, :EVENTINFO.OPTIME); 
5   END; 
6   /
操作已执行
已用时间: 34.589(毫秒). 执行号:8434.
SQL>

创建DDL 测试数据:

SQL> CREATE USER L01_TRI_10000 IDENTIFIED BY L01_TRI_10000; 
操作已执行
已用时间: 24.593(毫秒). 执行号:8435.
SQL> CREATE TABLE T03_TRI_10000(C1 INT); 
操作已执行
已用时间: 19.170(毫秒). 执行号:8436.
SQL> CREATE VIEW V01_TRI_10000 AS SELECT * FROM T01_TRI_10000; 
操作已执行
已用时间: 24.002(毫秒). 执行号:8437.
SQL> CREATE INDEX I01_TRI_10000 ON T01_TRI_10000(OBJECTTYPE); 
操作已执行
已用时间: 24.276(毫秒). 执行号:8438.
SQL> CREATE OR REPLACE PROCEDURE P01_TRI_10000 AS BEGIN SELECT * FROM 
2   T02_TRI_10000; END; 
3   /
操作已执行
已用时间: 26.278(毫秒). 执行号:8439.
SQL> CREATE FUNCTION F01_TRI_10000 RETURN VARCHAR(30) AS A1 VARCHAR(30); BEGIN 
2   SELECT C2 INTO A1 FROM T02_TRI_10000 WHERE C1=1; PRINT A1; RETURN A1; END; 
3   /
操作已执行
已用时间: 27.806(毫秒). 执行号:8440.
SQL> CREATE ROLE R01_TRI_10000;
操作已执行
已用时间: 6.706(毫秒). 执行号:8441.
SQL> CREATE SEQUENCE S01_TRI_10000 INCREMENT BY 10; 
操作已执行
已用时间: 13.231(毫秒). 执行号:8442.
SQL> CREATE TRIGGER TRI02_TRI_10000 AFTER CREATE ON DATABASE BEGIN PRINT 
2   'SUCCESS';END; 
3   /
操作已执行
已用时间: 17.455(毫秒). 执行号:8443.
SQL>

验证触发器数据:

https://www.cndba.cn/dave/article/116500

SQL> SELECT OBJECTTYPE, OBJECTNAME, SCHEMANAME, DATABASENAME, OPUSER FROM T01_TRI_10000; 

行号     OBJECTTYPE OBJECTNAME      SCHEMANAME DATABASENAME OPUSER
---------- ---------- --------------- ---------- ------------ ------
1          USER       L01_TRI_10000   NULL       dave         SYSDBA
2          TABLE      T03_TRI_10000   SYSDBA     dave         SYSDBA
3          VIEW       V01_TRI_10000   SYSDBA     dave         SYSDBA
4          INDEX      I01_TRI_10000   SYSDBA     dave         SYSDBA
5          PROCEDURE  P01_TRI_10000   SYSDBA     dave         SYSDBA
6          FUNCTION   F01_TRI_10000   SYSDBA     dave         SYSDBA
7          ROLE       R01_TRI_10000   NULL       dave         SYSDBA
8          SEQUENCE   S01_TRI_10000   SYSDBA     dave         SYSDBA
9          TRIGGER    TRI02_TRI_10000 SYSDBA     dave         SYSDBA

9 rows got

已用时间: 1.224(毫秒). 执行号:8444.

3.3 系统触发事件使用示例

只要一登录,服务器就会打印出 SUCCESS

SQL> create or replace trigger test_trigger 
2   after LOGIN on database 
3   begin 
4   print'SUCCESS'; 
5   end; 
6   /
SUCCESS

操作已执行
已用时间: 16.033(毫秒). 执行号:8445.
SQL>

4其他操作

4.1 编译触发器

语法:

ALTER TRIGGER [<模式名>.]<触发器名> COMPILE [DEBUG]; https://www.cndba.cn/dave/article/116500

查看触发器状态:

SQL> select OWNER,OBJECT_NAME,STATUS from dba_objects where OBJECT_TYPE='TRIGGER';

行号     OWNER  OBJECT_NAME             STATUS
---------- ------ ----------------------- ------
1          SYSDBA DMHS_DDL_TRIGGER_AFTER  VALID
2          SYSDBA DMHS_DDL_TRIGGER_BEFORE VALID
3          SYSDBA DMHS_DDL_TRIGGER_GRANT  VALID
4          SYSDBA DMHS_DDL_TRIGGER_REVOKE VALID
5          SYSDBA TEST_TRIGGER            VALID
6          SYSDBA TIMER1                  VALID
7          SYSDBA TIMER2                  VALID
8          SYSDBA TRG_INS_AFTER           VALID
9          SYSDBA TRG_INS_BEFORE          VALID
10         SYSDBA TRI01_TRI_10000         VALID
11         SYSDBA TRI02_TRI_10000         VALID
12         SYSDBA TRI1                    VALID
13         SYSDBA TRIT2                   VALID

13 rows got

已用时间: 13.144(毫秒). 执行号:8450.

当触发器无效时,可以重新编译:https://www.cndba.cn/dave/article/116500

SQL> ALTER TRIGGER SYSDBA.TRI1 COMPILE;
操作已执行
已用时间: 12.273(毫秒). 执行号:8451.
SQL>

4.2 禁止和允许触发器

语法:

ALTER TRIGGER [<模式名>.]<触发器名> ;

SQL>  ALTER TRIGGER SYSDBA.TRI1 DISABLE;

SQL>  select OWNER,TRIGGER_NAME,STATUS from dba_triggers;

行号     OWNER  TRIGGER_NAME            STATUS
---------- ------ ----------------------- ------
1          SYSDBA DMHS_DDL_TRIGGER_AFTER  Y
2          SYSDBA DMHS_DDL_TRIGGER_BEFORE Y
3          SYSDBA DMHS_DDL_TRIGGER_GRANT  Y
4          SYSDBA DMHS_DDL_TRIGGER_REVOKE Y
5          SYSDBA TEST_TRIGGER            Y
6          SYSDBA TIMER1                  Y
7          SYSDBA TIMER2                  Y
8          SYSDBA TRG_INS_AFTER           Y
9          SYSDBA TRG_INS_BEFORE          Y
10         SYSDBA TRI01_TRI_10000         Y
11         SYSDBA TRI02_TRI_10000         Y
12         SYSDBA TRI1                    N
13         SYSDBA TRIT2                   Y

13 rows got

已用时间: 7.533(毫秒). 执行号:68411.
SQL>

事件触发器也是一样操作:

SQL> ALTER TRIGGER SYSDBA.test_trigger DISABLE;
操作已执行
已用时间: 7.033(毫秒). 执行号:68412.
SQL>  select OWNER,TRIGGER_NAME,STATUS from dba_triggers;

行号     OWNER  TRIGGER_NAME            STATUS
---------- ------ ----------------------- ------
1          SYSDBA DMHS_DDL_TRIGGER_AFTER  Y
2          SYSDBA DMHS_DDL_TRIGGER_BEFORE Y
3          SYSDBA DMHS_DDL_TRIGGER_GRANT  Y
4          SYSDBA DMHS_DDL_TRIGGER_REVOKE Y
5          SYSDBA TEST_TRIGGER            N
6          SYSDBA TIMER1                  Y
7          SYSDBA TIMER2                  Y
8          SYSDBA TRG_INS_AFTER           Y
9          SYSDBA TRG_INS_BEFORE          Y
10         SYSDBA TRI01_TRI_10000         Y
11         SYSDBA TRI02_TRI_10000         Y
12         SYSDBA TRI1                    N
13         SYSDBA TRIT2                   Y

13 rows got

已用时间: 4.148(毫秒). 执行号:68413.
SQL>

4.3 删除触发器

语法:https://www.cndba.cn/dave/article/116500

DROP TRIGGER [IF EXISTS] [<模式名>.]<触发器名>;

SQL> DROP TRIGGER SYSDBA.TRI1;
操作已执行
已用时间: 24.707(毫秒). 执行号:68414.
SQL>

5 官方手册示例

5.1 引用完整性维护

删除被引用表中的数据时,级联删除引用表中引用该数据的记录;
更新被引用表中的数据时,更新引用表中引用该数据的记录的相应字段。https://www.cndba.cn/dave/article/116500

下例中,表 OTHER.DEPTTAB 为被引用表,其主关键字为 Deptno;表 OTHER.EMPTAB 为引用表。其结构如下:

CREATE OR REPLACE TRIGGER Dept_del_upd_cascade 
AFTER DELETE OR UPDATE ON OTHER.DEPTTAB FOR EACH ROW 
BEGIN 
IF DELETING THEN 
DELETE FROM OTHER.EMPTAB WHERE Deptno = :old.Deptno; 
ELSE 
UPDATE OTHER.EMPTAB SET Deptno = :new.Deptno WHERE Deptno = :old.Deptno; 
END IF; 
END;

5.2 CHECK 规则检查

增加新员工或者调整员工工资时,保证其工资不超过规定的范围,并且涨幅不超过 25%。
该例中,表 OTHER.EMPTAB 记录员工信息;表 OTHER.SALGRADE 记录各个工种的工资范围,其结构如下:

SET SCHEMA OTHER; 
CREATE OR REPLACE TRIGGER Salary_check 
BEFORE INSERT OR UPDATE ON OTHER.EMPTAB 
FOR EACH ROW
DECLARE 
Minsal FLOAT; 
Maxsal FLOAT; 
Salary_out_of_range EXCEPTION FOR -20002; 
BEGIN 
/* 取该员工所属工种的工资范围 */ 
SELECT Losal, Hisal INTO Minsal, Maxsal FROM OTHER.SALGRADE WHERE Job_classification = :new.Job; 
/* 如果工资超出工资范围,报告异常 */ 
IF (:new.Sal < Minsal OR :new.Sal > Maxsal) THEN 
RAISE Salary_out_of_range; 
END IF; 

/* 如果工资涨幅超出 25%,报告异常 */ 
IF UPDATING AND (:new.Sal - :old.Sal)/:old.Sal > 0.25 THEN 
RAISE Salary_out_of_range; 
END IF; 
END; 
SET SCHEMA SYSDBA;

5.3 使用触发器保障数据安全性

在复杂的条件下,可以使用触发器来保障数据的安全性。同样,要注意不要用触发器来实现 DM 安全机制已提供的功能。

使用触发器进行安全控制时,应使用语句级 BEFORE 类型的触发器,其优点如下:
1.在执行触发事件之前进行安全检查,可以避免系统在触发语句不能通过安全检查的
情况下做不必要的工作;
2.使用语句级触发器,安全检查只需要对每个触发语句进行一次,而不必对语句影响
的每一行都执行一次。

下面这个例子显示如何用触发器禁止在非工作时间内修改表 OTHER.EMPTAB 中的工资 (Sal)栏。非工作时间包括周末、公司规定的节假日以及下班后的时间。为此,我们用表OTHER.C OMPANYHOLIDAYS 来记录公司规定的节假日。

SET SCHEMA OTHER; 
CREATE OR REPLACE TRIGGER Emp_permit_changes 
BEFORE INSERT OR DELETE OR UPDATE 
ON OTHER.EMPTAB 
DECLARE 
Dummy INTEGER; 
Invalid_Operate_time EXCEPTION FOR -20002; 
BEGIN 
/* 检查是否周末 */ 
IF (DAYNAME(Sysdate) = 'Saturday' OR DAYNAME(Sysdate) = 'Sunday')  
RAISE Invalid_Operate_time; 
END IF; 
/* 检查是否节假日 */ 
SELECT COUNT(*) INTO Dummy FROM OTHER.COMPANYHOLIDAYS WHERE Holiday= Current_date; 
IF dummy > 0 THEN 
RAISE Invalid_Operate_time; 
END IF; 
/* 检查是否上班时间 */ 
IF (EXTRACT(HOUR FROM Current_time) < 8 OR EXTRACT(HOUR FROM Current_time) >= 18) THEN 
RAISE Invalid_Operate_time; 
END IF; 
END; 
SET SCHEMA SYSDBA;

5.4 使用触发器生成字段默认值

触发器还经常用来自动生成某些字段的值,这些字段的值有时依赖于本记录中的其他字段的值,有时是为了避免用户直接对这些字段进行修改。这类触发器应该是元组级 BEFORE INSERT 或 UPDATE 触发器。因为:
1.必须在 INSERT 或 UPDATE 操作执行之前生成字段的值;
2.必须为每条元组自动生成一次字段的值。

SET SCHEMA OTHER; 
CREATE OR REPLACE TRIGGER Emp_auto_value 
BEFORE INSERT 
ON OTHER.EMPTAB 
FOR EACH ROW 
BEGIN 
:new.Sal = 999.99; 
END; 
SET SCHEMA SYSDBA;

版权声明:本文为博主原创文章,未经博主允许不得转载。

用户评论
* 以下用户言论只代表其个人观点,不代表CNDBA社区的观点或立场
dave

dave

关注

人的一生应该是这样度过的:当他回首往事的时候,他不会因为虚度年华而悔恨,也不会因为碌碌无为而羞耻;这样,在临死的时候,他就能够说:“我的整个生命和全部精力,都已经献给世界上最壮丽的事业....."

  • 2237
    原创
  • 2
    翻译
  • 535
    转载
  • 185
    评论
  • 访问:6531617次
  • 积分:4229
  • 等级:核心会员
  • 排名:第1名
精华文章
    最新问题
    查看更多+
    热门文章
      热门用户
      推荐用户
        Copyright © 2016 All Rights Reserved. Powered by CNDBA · 皖ICP备2022006297号-1·

        QQ交流群

        注册联系QQ