如何在 PL/SQL 中编写语句级触发器

Posted

技术标签:

【中文标题】如何在 PL/SQL 中编写语句级触发器【英文标题】:How to write a statement level trigger in PL/SQL 【发布时间】:2018-05-21 03:30:34 【问题描述】:
CREATE TABLE faculty
(f_id NUMBER(6),
f_last VARCHAR2(15),
f_first VARCHAR2(15),
f_mi CHAR(1),
loc_id NUMBER(5) not null,
f_phone VARCHAR2(10),
f_rank VARCHAR2(9),
f_salary number(9,2), 
f_super NUMBER(6), --supervisor/manager of the faculty member
f_pin NUMBER(4),
f_image BLOB, 
CONSTRAINT faculty_f_id_pk PRIMARY KEY(f_id),
CONSTRAINT faculty_loc_id_fk FOREIGN KEY (loc_id) REFERENCES location(loc_id));

--- inserting records into FACULTY
INSERT INTO faculty VALUES
(1, 'Marx', 'Teresa', 'J', 9, '4075921695', 'Associate', 75000.00, 4, 6338, EMPTY_BLOB());

INSERT INTO faculty VALUES
(2, 'Zhulin', 'Mark', 'M', 10, '4073875682', 'Full', 98000.00, NULL, 1121, EMPTY_BLOB());

INSERT INTO faculty VALUES
(3, 'Langley', 'Colin', 'A', 12, '4075928719', 'Assistant', 60000.00, 4, 9871, EMPTY_BLOB());

INSERT INTO faculty VALUES
(4, 'Brown', 'Jonnel', 'D', 11, '4078101155', 'Full', 102000.00, NULL, 8297, EMPTY_BLOB());

INSERT INTO faculty VALUES
(5, 'Sealy', 'James', 'L', 13, '4079817153', 'Associate', 80000.00, 1, 6089, EMPTY_BLOB());

我已经写了这个 ROW 级别触发器(在下面),但不知道如何获得一个可以做同样事情的语句级别触发器。因为不能使用 :NEW / :OLD 在语句级别,然后混淆...

--Row Level
create or replace TRIGGER TRG_F_SALARY_CHECK
BEFORE INSERT OR UPDATE OF F_SUPER ON FACULTY
FOR EACH ROW

BEGIN
    IF :NEW.F_SUPER > :OLD.F_SUPER THEN
        :NEW.F_SALARY := :OLD.F_SALARY + 2000*(:NEW.F_SUPER - 5);
        DBMS_OUTPUT.PUT_LINE('The salary has been updated');
    END IF;
    IF :NEW.F_SUPER < :OLD.F_SUPER THEN
        IF :OLD.F_SUPER >=5 THEN
            IF :NEW.F_SUPER < 5 THEN
                :NEW.F_SALARY := :OLD.F_SALARY - 2000*(:OLD.F_SUPER - 5);
                DBMS_OUTPUT.PUT_LINE('The salary has been updated');
            ELSE
              :NEW.F_SALARY := :OLD.F_SALARY - 2000*(:OLD.F_SUPER - :NEW.F_SUPER);
              DBMS_OUTPUT.PUT_LINE('The salary has been updated');
            END IF;
        END IF;
    END IF;
END;

create or replace TRIGGER TRG_F_SALARY_CHECK_STATEMENT
BEFORE INSERT OR UPDATE OF F_SUPER, F_SALARY ON FACULTY
DECLARE
  --  OLD_F_SUPER NUMBER(10);
    OLD_F_SALARY NUMBER(9);
BEGIN
--        SELECT F_SUPER INTO OLD_F_SUPER FROM FACULTY;
--       SELECT SUM(F_SALARY) INTO OLD_F_SALARY FROM FACULTY
--       WHERE F_ID;
   UPDATE FACULTY
   /* SET F_SALARY = F_SALARY + 2000*(F_SUPER -5)
        WHERE F_SUPER > 5;*/
        SET F_SALARY = OLD_F_SALARY + 2000*(F_SUPER - 5)
            WHERE F_SUPER > 5;
END;

顺便说一句,表FACULTY 包含在F_IDF_SALARYF_SUPER 等中。我将获得** 单行触发器**(已经完成)和一个语句触发器 用于通过更改F_SUPER 号码来更新教师的薪水。 对于 5 之后的每一个 F_SUPER 更改(增加或减少),F_SALARY 将更改(增加或减少)$ 2000。

测试代码如下:

/*F_ID = 5, F_SUPER = 7, F_SALARY = 84000*/
UPDATE FACULTY
SET F_SUPER = 7
WHERE F_ID = 5;
/*F_ID =5, F_SUPER = 2, F_SALARY = 80000*/ 
UPDATE FACULTY
SET F_SUPER = 2
WHERE F_ID = 5;

谢谢

【问题讨论】:

如果您解释业务规则而不是让我们尝试从您的代码中对它们进行逆向工程,这将对我们有所帮助。 【参考方案1】:

我已经写了这个 ROW 级别触发器(在下面),但不知道如何 获得一个语句级触发器,它可以做同样的事情 这。并且因为不能在语句级别使用 :NEW / :OLD ,所以 迷茫……

语句级触发器和行级触发器不一样。它们由 Oracle 根据使用情况提供。因此,不能用语句级触发器替换所有行级触发器。见下面的定义和用法:

数据相关活动的行级触发器

• 行级触发器对事务中的每一行执行一次。

• 行级触发器是最常见的触发器类型。他们是 常用于数据审计应用中。

• 行级触发器由 FOR EACH ROW 子句标识 创建触发器命令。

事务相关活动的语句级触发器

• 语句级触发器为每个事务执行一次。为了 例如,如果单个事务将 500 行插入到客户 表,那么该表上的语句级触发器只会是 执行一次。

• 因此,语句级触发器不常用于 与数据相关的活动;它们通常用于强制执行额外的 可能执行的交易类型的安全措施 在桌子上。

• 语句级触发器是创建的默认触发器类型 并通过省略 CREATE 中的 FOR EACH ROW 子句来标识 触发命令。

语句级触发器示例:

CREATE or REPLACE TRIGGER Before_Update_Stat_product 
BEFORE UPDATE ON product 
Begin 
  INSERT INTO table  
  Values('Before update, statement level',sysdate); 
END; 
/ 

【讨论】:

【参考方案2】:

他想用语句级触发器更新整个表(带过滤器),而 IMO 触发器应该是“在插入或更新之后”。

【讨论】:

这应该是评论而不是答案。而且,你不会猜到是“他”

以上是关于如何在 PL/SQL 中编写语句级触发器的主要内容,如果未能解决你的问题,请参考以下文章

什么是PL/SQL

语句触发器 PL/SQL

oracle 学习笔记之触发器

PL/SQL 07 触发器 trigger

PL/SQL 触发器在插入语句之前检查值

如何在 Pl/SQL 中编写正则表达式匹配模式?