Oracle - 在不检查约束的情况下触发BEFORE INSERT

时间:2015-04-29 09:38:42

标签: oracle plsql triggers

我有这张表描述某种图书馆的书籍贷款:

ImageListView

我想制作一个触发器,当您插入新贷款时,将贷款日期设置为今天,并将当天的返还日期设置为+ 21天。有代码,有效:

create table emprunt (
    num_ab number(6,0) REFERENCES abonne(numero),
    num_ex number (4,0) REFERENCES exemplaire(numero),
    d_emprunt date,
    d_retour date,
    d_ret_reel date,
    nb_relance number(1,0) CHECK (nb_relance IN (1,2,3)),
    CONSTRAINT pk_emprunt PRIMARY KEY (num_ab, num_ex, d_emprunt)
);

但是问题是不再检查表格中的主要约束...例如,如果我多次

CREATE OR REPLACE TRIGGER on_insert_emprunt
BEFORE INSERT ON emprunt
FOR EACH ROW
BEGIN
    :NEW.d_emprunt := SYSDATE;
    :NEW.d_retour := SYSDATE + 21;
END;
/

它完美无缺......而不是说我:

  

违反了UNIQUE CONSTRAINT

我在表格中有多个相同的行...

PS:抱歉用法语表。

2 个答案:

答案 0 :(得分:1)

与所有Oracle日期一样,

SYSDATE具有时间组件。您重复插入的时间与触发器的时间不同,除非您碰巧在一秒钟内进行两次插入,否则您不会看到约束违规。日期不同(下至时间级别),因此用于主键的值不同 - 因此没有约束违规。

通过查询,您可以看到主键不同:

SELECT TO_CHAR(d_emprunt, 'YYYY-MM-DD HH24:MI:SS') AS d_emprunt,
  TO_CHAR(d_retour, 'YYYY-MM-DD HH24:MI:SS') AS d_retour
FROM emprunt
WHERE num_ab = 921102
AND num_ex = 1010;

D_EMPRUNT           D_RETOUR          
------------------- -------------------
2015-04-29 10:55:30 2015-05-20 10:55:30
2015-04-29 10:55:35 2015-05-20 10:55:35

您会看到所插入的所有记录的时间不尽相同。

如果您想将日期设置为午夜you can truncate them,默认情况下会将时间组件重置为零:

CREATE OR REPLACE TRIGGER on_insert_emprunt
BEFORE INSERT ON emprunt
FOR EACH ROW
BEGIN
    :NEW.d_emprunt := TRUNC(SYSDATE);
    :NEW.d_retour := TRUNC(SYSDATE) + 21;
END;
/

顺便说一句,您的主键看起来效果不是很好。如果意图是阻止同一本书同时借出两次,那就不是那么做了。它阻止了这本书在同一天出借,但不是重叠期间。因此,如果我明天拿出同一本书,主键值仍然是唯一的,但范围会重叠。

答案 1 :(得分:0)

主键检查

 (num_ab, num_ex, d_emprunt)

作为一个整体独特。

当您将数据num_ab and num_ex插入相同但d_empruntsysdate时。 它正在改变。

如果您在1秒内插入两次数据,则会收到错误。