【问题标题】:Insert trigger to validate unique constraint插入触发器以验证唯一约束
【发布时间】:2012-06-15 17:54:15
【问题描述】:

updated 变为Y 时,我有以下触发器。仅当 my_hist 表中不存在值时,我才想插入旧值。如果存在相同的记录,则不应插入。对于这个最好的方法是创建一个约束来检查my_hist表中的唯一性还是在触发器中检查这个条件?如果是这样,我怎么能在触发器中做到这一点?

或者是否可以在触发器中检查my_hist表的唯一约束,使其不会插入重复记录。

CREATE OR REPLACE TRIGGER mytrig
    AFTER UPDATE
    ON mytab
    FOR EACH ROW
WHEN (
new.updated = 'Y'
      )
BEGIN
    INSERT INTO my_hist
      VALUES   (
                        :old.id,
                        :old.no,                        
                        :old.start_date,
                        :old.end_date,
                        SYSDATE
                  );
END mytrig;
/

【问题讨论】:

    标签: database plsql triggers oracle10g constraints


    【解决方案1】:

    您可以将insert 更改为以下内容,以检查是否已存在重复项。选择假设my_hist 的主键是idstart_date,将where not exists 子句更改为仅使用不同的主键值。

    insert into my_hist
    select :old.id, :old.no, :old.start_date, :old.end_date, sysdate
      from dual
     where not exists ( select 1
                          from my_hist
                         where id = :old.id
                           and start_date = :old.start_date
                               )
    

    但是,这需要进行索引扫描,因此不是最优的。

    而是让异常被引发。它被明确命名为:dup_val_on_index。如果这确实被提出,那么只需忽略它。

    BEGIN
        INSERT INTO my_hist
          VALUES   (
                            :old.id,
                            :old.no,                        
                            :old.start_date,
                            :old.end_date,
                            SYSDATE
                      );
    -- ignore an exception that get's raised if a duplicate value
    -- gets inserted. 
    EXCEPTION WHEN DUP_VAL_ON_INDEX then null;
    END mytrig;
    

    【讨论】:

    • 感谢您的解决方案。赞赏。
    【解决方案2】:

    如果要强制执行唯一性,请使用唯一性约束。这总是比自己编写代码更可取。

    您可以在INSERT 语句中检查该行是否已存在

    INSERT INTO my_hist( id, 
                         no, 
                         start_date, 
                         end_date, 
                         some_other_column )
      SELECT :old.id, 
             :old.no, 
             :old.start_date,
             :old.end_date,
             sysdate
        FROM dual
       WHERE NOT EXISTS( SELECT 1
                           FROM my_hist
                          WHERE my_hist.id = :old.id
                            AND my_hist.no = :old.no
                            AND my_hist.start_date = :old.start_date
                            AND my_hist.end_date   = :old.end_date );
    

    但是,在多个会话可能同时插入同一行的多用户环境中,这将不起作用。

    【讨论】:

    • 谢谢贾斯汀。是否可以在触发器中引用约束,以便在违反约束时我可以在触发器中有条件然后不触发触发器?
    • @Polappan - 您当然可以让触发器尝试执行INSERT,然后捕获如果违反约束将引发的dup_val_on_index 异常。
    • 感谢 cmets 和解决方案。赞赏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-08
    • 2013-05-21
    • 2020-04-17
    相关资源
    最近更新 更多