【问题标题】:Need to insert single record into the audit table after trigger is called调用触发器后需要向审计表中插入单条记录
【发布时间】:2022-01-19 08:52:09
【问题描述】:
CREATE TABLE trg_demo 
(
    e_id    NUMBER(10),
    e_name  VARCHAR2(30),
    CONSTRAINT pk_trg_demo PRIMARY KEY (e_id)
);

CREATE SEQUENCE trg_audit_sq;

CREATE TABLE trg_audit 
(
    a_id           NUMBER(10),
    modified_date  TIMESTAMP,

    CONSTRAINT pk_trg_audit PRIMARY KEY (a_id)
);

触发器:

CREATE OR REPLACE TRIGGER trigger_trg
BEFORE INSERT
ON trg_demo
FOR EACH ROW
BEGIN
    INSERT INTO trg_audit 
    VALUES (trg_audit_sq.nextval, current_timestamp);
END;
INSERT INTO trg_demo VALUES (1, 'A');
INSERT INTO trg_demo VALUES (2, 'B');

预期输出:

+------+---------------+
| A_ID | MODIFIED_DATE |
+------+---------------+
|    1 | 16-12-21      |
+------+---------------+

我将在 2 天内向 trg_demo 表中插入一次行。所以,假设今天如果我插入 2 行然后在 trg_audit 表中,它将只插入今天日期的一行,然后如果我在 trg_demo 表中插入 4 行然后在 2 天后在 trg_audit 中它将有第二行,A_ID 为 2,日期为 18-12-21

【问题讨论】:

  • select * from user_errors where type = 'TRIGGER' and name = 'trigger_trg' 有什么错误?
  • 你的代码很好。我怀疑这可能是某种授予/许可问题。检查您的触发器是否编译正确。错误说它无效
  • @AliFidanli 谢谢触发器有错误。但我可以看到审计表中插入了两行,但我只需要插入一条记录,如原始问题所示
  • 当您创建了一个行级触发器(FOR EACH ROW,对吗?),它会为您运行的每个 INSERT 语句触发。如果您运行了两次插入,则会将两行插入到日志表中。这是意料之中的,你是这样写的。也许您想切换到语句级触发器。
  • @Littlefoot感谢您的建议。如何做语句级触发?

标签: sql oracle plsql


【解决方案1】:

请注意,虽然触发器可以将数据添加到审计表中,但请确保对正在使用的触发器进行 2 次更新 -

  1. 如果您希望每次数据加载向表中插入 1 行以避免重复的审计详细信息,请使用语句级触发器。

  2. 尽可能使用 AFTER insert 因为知道插入是否发生的真正方法是在插入之后触发它,以防插入实际上由于数据约束要求而失败,除非您的要求是跟踪 evert在特定表上插入尝试。

    创建或替换触发器customers_credit_trg

          AFTER INSERT ON trg_demo
    
             FOR EACH ROW
    
              BEGIN
    
              INSERT INTO trg_audit VALUES (trg_audit_sq.nextval, 
                current_timestamp);
    
         END;
    

【讨论】:

    【解决方案2】:

    您可以在触发器中使用条件来阻止其余的,并且只接受一条记录:

    CREATE OR REPLACE TRIGGER trigger_trg
    BEFORE INSERT
    ON trg_demo
    FOR EACH ROW
      declare 
    flag number;
    BEGIN
    
    select count(*) into flag from trg_audit d where trunc(d.modified_date) = trunc(sysdate) ;
    
    if flag < 1 then 
        INSERT INTO trg_audit
        VALUES (trg_audit_sq.nextval, current_timestamp);
        end if ;
    END;
    

    【讨论】:

    • 感谢您的快速周转,但这将如何工作如果我将记录插入trg_demo,因为它正在检查flag&lt;1,那么下次标志计数将为2,那么插入将如何在@ 987654324@
    • flag 每天都会为 0,因为它会检查 trg_audit 表是否有当天的记录。如果还没有记录,它将插入
    • @vicky 您可能需要考虑使用 IDENTITY 列而不是序列,因为这是您在数据库中需要的少一个对象,您可以从代码中删除 sequence.nextval。 seq_num integer GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,我设计的每个表都使用它来唯一标识单行。请注意,它可以是 PRIMARY KEY,但也不是。
    猜你喜欢
    • 1970-01-01
    • 2021-09-05
    • 2021-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-07
    • 2013-06-11
    相关资源
    最近更新 更多