Oracle SQL 使用触发器检查重叠日期

Oracle SQL checking for overlapped dates using a trigger

我有 table 名为 EPOCA 的架构:

CREATE TABLE EPOCA
(
    ID       INT
        CONSTRAINT PK_EPOCA PRIMARY KEY,
    NOME     VARCHAR(250),
    DATE_INITIAL DATE
        CONSTRAINT NN_EPOCA_DATA_INI NOT NULL,
    DATE_END DATE,
    CONSTRAINT CK_EPOCA_DATAS CHECK (DATE_INITIAL < DATE_END)
);

即使我已经检查了初始日期是否小于结束日期,我仍需要检查当我插入一个新的 EPOCA 时,我插入的日期不会与任何当前日期重叠。

我开发了这个触发器:

CREATE OR REPLACE TRIGGER TRGEPOCASNAOSOBREPOSTAS
BEFORE INSERT OR UPDATE
ON EPOCA
FOR EACH ROW

DECLARE
    FLAG_DATE NUMBER;
BEGIN
    FLAG_DATE := 0;

    IF INSERTING THEN
        SELECT E.ID INTO FLAG_DATE FROM EPOCA E WHERE E.DATE_INITIAL < :NEW.DATE_INITIAL AND E.DATE_END > :NEW.DATE_END;
        IF FLAG_DATE <> 0 THEN
            RAISE_APPLICATION_ERROR(-2098, 'INSERT FAILED BECAUSE SELECTED DATES OVERLAP EXISTENT ONES');
        END IF;
    ELSIF UPDATING THEN
        SELECT E.ID INTO FLAG_DATE FROM EPOCA E WHERE E.DATE_INITIAL < :NEW.DATE_INITIAL AND E.DATA_END > :NEW.DATA_END;
        IF FLAG_DATE <> 0 THEN
            RAISE_APPLICATION_ERROR(-2099, 'UPDATE FAILED BECAUSE SELECTED DATES OVERLAP EXISTENT ONES');
        END IF;
    END IF;
END;

我在插入时遇到的错误是因为在触发器的第 7 行没有找到数据,而当我更新 table 时出现错误是因为 table 处于突变状态并且trigger cannot read the table,这是有道理的,但我不知道如何解决它。

关于如何解决这个问题有什么建议吗?

您不需要 SELECT 语句,但将您的代码转换为如下所示的代码

CREATE OR REPLACE TRIGGER TRGEPOCASNAOSOBREPOSTAS
BEFORE UPDATE
ON EPOCA
FOR EACH ROW
DECLARE
    FLAG_DATE NUMBER;
BEGIN
    FLAG_DATE := 0;

    IF UPDATING THEN
        IF :OLD.DATE_INITIAL < :NEW.DATE_INITIAL AND :OLD.DATE_END > :NEW.DATE_END THEN
           FLAG_DATE := :OLD.ID;
        END IF;
        IF FLAG_DATE <> 0 THEN
            RAISE_APPLICATION_ERROR(-2099, 'UPDATE FAILED BECAUSE SELECTED DATES OVERLAP EXISTENT ONES');
        END IF;
    END IF;
END;
/

无需使用 INSERTING 大小写(触发器应仅 BEFORE UPDATE)。由于所需条件已作为 table 定义中的检查约束提供。

您应该在 select 查询中的两个地方都使用 count 聚合函数,因为它总是 returns tge 计数,即使它为零,如下所示:

...
...
SELECT count(*) INTO FLAG_DATE FROM EPOCA E WHERE E.DATA_INI < :NEW.DATA_INI AND E.DATA_FIM > :NEW.DATA_FIM;
IF FLAG_DATE <> 0 THEN
...
...