【问题标题】:Creating a Trigger in Oracle to check date between tables在 Oracle 中创建触发器以检查表之间的日期
【发布时间】:2017-08-02 15:53:54
【问题描述】:

我的 Oracle 数据库中有 2 个表

CLIENT_ID(PK) -  INSERT_DATE

    1         -  1/1/2017  


CLIENT_ID(FK) -  EXIT_DATE

    1         -  5/1/2017

我想创建一个插入前触发器,如果​​我尝试在 EXIT_DATE 上插入比 INSERT_DATE 列更早的日期,它将显示错误。

例如,如果我尝试插入 2016 年 12 月 31 日,它将显示错误“退出日期不能早于插入日期”我的问题还在于触发器必须在两个表之间也匹配 Client_ID。 (我用的是 Oracle 11g)

【问题讨论】:

  • 触发器无法显示错误消息,因为它们无法与任何类型的用户界面进行交互。将这种检查放入您的应用程序中。祝你好运。
  • 你到底是什么意思?
  • 您可以在触发器中引发异常。
  • @NikosL24:错误检查是由离线代码实现的,就像在触发器中一样,它将异常炸弹扔到代码流中是一团糟,一团糟维持。想一想:你是一个不错的小应用程序,对你的业务很开心,你完成了一个复杂的事务,你要去向表中插入一行。突然,一个异常突然出现在你家门口!你没有做任何事情来挑起这件事,但现在处理它是你的问题。 “要是我先检查错误就好了!”,你哭了,“要是……!!!”

标签: oracle triggers insert


【解决方案1】:

已编辑,其中包含 FOREIGN KEY 防止孤儿 CLIENT_IDs 的信息。

要生成执行您所描述的规则的触发器,以下方法将起作用。
首先,创建一些测试表:

CREATE TABLE INSERT_TABLE(
  CLIENT_ID NUMBER NOT NULL PRIMARY KEY,
  INSERT_DATE DATE NOT NULL
);

CREATE TABLE EXIT_TABLE(
  CLIENT_ID NUMBER NOT NULL REFERENCES INSERT_TABLE(CLIENT_ID),
  EXIT_DATE DATE NOT NULL
);
CREATE INDEX EXIT_INSERT_FKI ON EXIT_TABLE(CLIENT_ID);

然后,应用触发器:

CREATE OR REPLACE TRIGGER EXIT_AFTER_INSERT_ENFORCER
BEFORE INSERT ON EXIT_TABLE
FOR EACH ROW
  DECLARE
    V_INSERT_DATE DATE;
  BEGIN
    SELECT INSERT_TABLE.INSERT_DATE
    INTO V_INSERT_DATE
    FROM INSERT_TABLE
    WHERE INSERT_TABLE.CLIENT_ID = :NEW.CLIENT_ID;

    IF :NEW.EXIT_DATE < V_INSERT_DATE
    THEN RAISE_APPLICATION_ERROR(-20100, 'EXIT DATE cannot be older than the INSERT DATE');
    END IF;
EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
  END;
/

注意:触发器不是完成此操作的唯一方法。 MATERIALIZED VIEW 也可以通过 CHECK CONSTRAINT 强制执行此约束。替代建模也将简化事情。我将在下面详细介绍另一种选择。

然后测试触发器:

以下是可以的:

INSERT INTO INSERT_TABLE VALUES (1, TO_DATE('20170101', 'YYYYMMDD'));
INSERT INTO EXIT_TABLE VALUES (1, TO_DATE('20170501', 'YYYYMMDD'));
1 row inserted.
1 row inserted.

但以下内容被阻止,因为退出日期早于插入日期:

INSERT INTO INSERT_TABLE VALUES (2, TO_DATE('20170101', 'YYYYMMDD'));
INSERT INTO EXIT_TABLE VALUES (2, TO_DATE('19910501', 'YYYYMMDD'));

ORA-20100:退出日期不能早于插入日期

这应该完成你所描述的。

作为额外的考虑,我想补充一点,替代数据模型可以帮助解决这样的约束。如果INSERT_DATEEXIT_DATE 都是同一个客户端的属性,那么只有一个表的替代设计可以更简单地执行此操作:

CREATE TABLE INSERT_EXIT(
  CLIENT_ID NUMBER NOT NULL PRIMARY KEY,
  INSERT_DATE DATE NOT NULL,
  EXIT_DATE DATE NULL,
  CONSTRAINT EXIT_AFTER_INSERT CHECK (EXIT_DATE >= INSERT_DATE)
);

在此表中,允许以下内容:

INSERT INTO INSERT_EXIT VALUES (1,TO_DATE('20170101', 'YYYYMMDD'),NULL);
INSERT INTO INSERT_EXIT VALUES (2,TO_DATE('20170101', 'YYYYMMDD'),TO_DATE('20170501', 'YYYYMMDD'));
1 row inserted.
1 row inserted.

但以下自然是不允许的:

INSERT INTO INSERT_EXIT VALUES (3,TO_DATE('20170101', 'YYYYMMDD'),TO_DATE('19700101', 'YYYYMMDD'));

ORA-02290:违反检查约束 (MYSCHEMA.EXIT_AFTER_INSERT)

【讨论】:

  • 我认为触发器起作用了。但是我收到关于触发器的这个错误。正常吗?保存对表“”的更改时出错。“EXIT_TABLE”:第 1 行:ORA-20100:退出日期不能早于 INSERT DATE ORA-06512:在“.EXIT_AFTER_INSERT_ENFORCER”,第 10 行 ORA-04088:触发器执行期间出错'.EXIT_AFTER_INSERT_ENFORCER' ORA-06512:在第 1 行
  • @NikosL24 对于给定的 CLIENT_ID,添加在 INSERT_DATE 之前的 EXIT_DATE 时,您应该会遇到这种异常。如果您在意外情况下遇到此异常,一些额外的数据会有所帮助;你可以用细节更新问题,我会看一下。
  • INSERT_TABLE 上的 Client_ID 是 PK,而 EXIT_TABLE 上的 Client_ID 是 FK。这有帮助吗?
  • 感谢@NikosL24。键的存在可以简化您的触发器并加强 EXIT_TABLE 中的每个 CLIENT_ID 必须具有比 INESERT_TABLE 更新的日期的约束,但不会改变太多。我将使用适当的密钥更新我的答案。我应该注意,触发器不是唯一可用的方法。物化视图可以强制执行此约束,如果这些日期都是同一 CLIENT 的属性,则可以使用替代模型。
  • 是的,我试过了,效果很好,但我仍然收到以下错误:ORA-06512 和 ORA-04088。正常吗?触发器有效,但它不允许我插入错误的日期。
猜你喜欢
  • 2016-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-23
  • 2020-10-22
  • 1970-01-01
  • 2013-12-24
相关资源
最近更新 更多