【问题标题】:Prevent record insert without mutating防止记录插入而不改变
【发布时间】:2023-02-03 14:14:59
【问题描述】:

我试图阻止将记录插入表中以进行调度。如果课程的开始日期介于之前记录的开始日期和结束日期之间,并且该记录与新记录的位置相同,则不应允许。

我编写了以下触发器,它可以编译,但当然会发生变异,因此存在问题。我研究了复合触发器来处理这个问题,但要么无法完成,要么我的理解不好,因为我也无法让它工作。我本以为对于一个复合触发器,我想在 before 语句上做这些事情,但我只得到了错误。

我也在插入/更新之后考虑过,但是在它已经插入之后不适用吗?感觉那是不对的……另外,我相信突变也有同样的问题。

我写的触发器是:

CREATE OR REPLACE TRIGGER PREVENT_INSERTS 
before insert or update on tbl_classes

    DECLARE
        v_count number;
        v_start TBL_CLASS_SCHED.start_date%type;
        v_end TBL_CLASS_SCHED.end_date%type;
        v_half TBL_CLASS_SCHED.day_is_half%type;
    BEGIN
        select start_date, end_date, day_is_half
        into v_start, v_end, v_half
        from tbl_classes 
        where class_id = :NEW.CLASS_ID
        and location_id = :NEW.location_id;

        select count(*) 
        into v_count 
        from TBL_CLASS_SCHED
        where :NEW.START_DATE >= (select start_date 
                                   from TBL_CLASS_SCHED 
                                   where class_id = :NEW.CLASS_ID
                                   and location_id = :NEW.location_id)
        and :NEW.START_DATE <= (select end_date
                                   from TBL_CLASS_SCHED
                                   where class_id = :NEW.CLASS_ID
                                   and location_id = :NEW.location_id);

        if (v_count = 2) THEN
            RAISE_APPLICATION_ERROR(-20001,'You cannot schedule more than 2 classes that are a half day at the same location');
        end if;
        if (v_count = 1 and :NEW.day_is_half = 1) THEN
            if (v_half != 1) THEN
                RAISE_APPLICATION_ERROR(-20001,'You cannot schedule a class during another class''s time period of the same type at the same location');
            end if;
        end if;
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            null;
    END;
    
end PREVENT_INSERTS ;

也许不能用触发器来完成,我需要通过多种方式来完成?现在我在直接插入或更新之前使用相同的逻辑完成了它,但我想将它作为约束/触发器,以便它始终适用(这样我就可以了解它)。

【问题讨论】:

    标签: database oracle plsql triggers constraints


    【解决方案1】:

    您需要修复两件事。

    1. 发生变异是因为您试图在触发器的行级部分执行 SELECT。查看 COMPOUND 触发器作为缓解这种情况的方法。基本上,您在行级别捕获信息,并在 after 语句级别处理该信息。我的视频中的一些例子https://youtu.be/EFj0wTfiJTw

    2. 即使解决了变异问题,由于并发性,这里的逻辑(触发器或其他)仍然存在根本缺陷。您所需要的只是(比方说)三四个人同时使用此代码。他们都会得到“是的,你的计数检查没问题”,因为他们都看不到彼此未提交的数据。因此,他们都被告知他们可以继续,当他们最终提交时,您将存储多行,因此违反了您的 tirgger(或您的代码运行的任何地方)试图执行的规则。您需要查看适当的行,以便控制对表的并发访问。对于 UPDATE,这很容易,因为这意味着位置/类配对已经有一些行。对于 INSERT,您需要确保在某处的父表上有适当的唯一约束。没有看到整个模型很难说

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-24
      • 1970-01-01
      • 2023-03-18
      • 2013-10-12
      • 2015-04-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多