插入触发器以验证唯一约束

时间:2012-06-12 19:37:51

标签: database plsql triggers oracle10g constraints

我有以下触发器,当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;
/

2 个答案:

答案 0 :(得分:3)

如果要强制实施唯一性,请使用唯一约束。这总是更适合自己编码。

您可以检查该行是否已作为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 );

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

答案 1 :(得分:1)

您可以将insert更改为以下内容,以检查是否已存在重复项。 select假定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;