【问题标题】:How to fix the code for trigger that prevent the insert based on some conditions如何修复基于某些条件阻止插入的触发器代码
【发布时间】:2019-10-23 08:50:46
【问题描述】:

我正在尝试创建一个我遇到问题的触发器。 触发器的工作是阻止项目插入。 这里有 2 个学生和科目表。 当学生没有注册该科目时,我必须检查并防止插入,如果他有,他将从下学期开始,所以目前他没有在那里注册。 请帮我解决这个问题。

CREATE OR REPLACE TRIGGER check_student 
BEFORE INSERT ON subject
FOR EACH ROW
BEGIN
    IF :new.student_no 
    AND :new.student_name  NOT IN (
        SELECT DISTINCT student_no,student_name 
        FROM student
    ) 
    OR :new.student_enrollment_date < (
        select min(enrolment_date) 
        from student 
        where 
            student.student_name = :new.student_name 
            and student.student_no = :new.guest_no 
        group by student.student_name , student.student_no
    )
    AND :new.student_name = (
        select distinct student_name 
        from student
    )
    AND :new.student_no = (
        select distinct student_no 
        from student
    )
    THEN
        raise_application_error(-20000, 'Person must have lived there');
    END IF;
END;
/

当学生没有注册该科目时,我必须检查并防止插入,如果他有,他将从下学期开始,所以目前他没有在那里注册。

请帮帮我。

【问题讨论】:

  • 你想要的输出是什么?

标签: sql oracle plsql database-trigger


【解决方案1】:

您的条件中可能存在逻辑优先级问题,因为它包含 ANDs 和 ORs 而没有任何括号。此外,您正在针对返回多于一行或多于一列的子查询检查标量值,这将产生运行时错误。

但总的来说,我认为您的代码可以通过使用唯一的 NOT EXISTS 条件和子查询来简化,该子查询会检查是否同时满足所有功能条件。这应该非常接近您想要的:

create or replace trigger check_student 
before insert on subject
for each row
begin
    if not exists (
        select 1
        from student
        where 
            name = :new.student_name 
            and student_no = :new.student_no
            and enrolment_date <= :new.student_enrollment_date 
    ) then
        raise_application_error(-20000, 'Person must have livd there');
    end if;
end;
/

注意:尚不清楚colum :new.guest_no 的用途是什么,所以我暂时将它放在一边(我假设您的意思是:new.student_no)。

【讨论】:

    【解决方案2】:

    您的代码很不清楚,所以我只是使用您在问题中使用的相同条件来让您知道如何继续。

    CREATE OR REPLACE TRIGGER CHECK_STUDENT BEFORE
        INSERT ON SUBJECT
        FOR EACH ROW
    DECLARE
        LV_STU_COUNT             NUMBER := 0; --declared the variables
        LV_STU_ENROLLED_FUTURE   NUMBER := 0;
    BEGIN
        SELECT
            COUNT(1)
        INTO LV_STU_COUNT -- assigning value to the variable
        FROM
            STUDENT
        WHERE
            STUDENT_NO = :NEW.STUDENT_NO
            AND STUDENT_NAME = :NEW.STUDENT_NAME;
    
        -- ADDED BEGIN EXCEPTION BLOCK HERE
        BEGIN
        SELECT
            COUNT(1)
        INTO LV_STU_ENROLLED_FUTURE -- assigning value to the variable
        FROM
            STUDENT
        WHERE
            STUDENT.STUDENT_NAME = :NEW.STUDENT_NAME
            AND STUDENT.STUDENT_NO = :NEW.GUEST_NO
        GROUP BY
            STUDENT.STUDENT_NAME,
            STUDENT.STUDENT_NO
        HAVING
            MIN(ENROLMENT_DATE) > :NEW.STUDENT_ENROLLMENT_DATE;
        EXCEPTION WHEN NO_DATA_FOUND THEN
           LV_STU_ENROLLED_FUTURE  := 0;
        END;
    
        -- OTHER TWO CONDITIONS SAME LIKE ABOVE, IF NEEDED
    
        -- using variables to raise the error
        IF LV_STU_COUNT = 0 OR ( LV_STU_ENROLLED_FUTURE >= 1 /* AND OTHER CONDITIONS*/ ) THEN
            RAISE_APPLICATION_ERROR(-20000, 'Person must have livd there');
        END IF;
    
    END;
    /
    

    干杯!!

    【讨论】:

    • INSERT INTO review VALUES (41,'位于绝佳位置的出色公寓,非常友好的工作人员和清洁人员做得很好!总体而言,这是一个完美的周末度假公寓',to_date('10 -03-2019','dd-mm-yyyy'),4,1,5);
    • 错误从行开始:96 in command - INSERT INTO review VALUES (41,'一个出色的公寓,位置绝佳,工作人员非常友好,清洁人员做得很好!总体而言,这是一个完美的公寓周末休息',to_date('10-03-2019','dd-mm-yyyy'),4,1,5) 错误报告 - ORA-01403:未找到数据 ORA-06512:在“PARO0004.CHECK_REVIEW” ,第 16 行 ORA-04088: 执行触发器“PARO0004.CHECK_REVIEW”时出错
    • 使用相同的触发器但遇到此问题。这是为了正确的输入。错误的输入被过滤,所以这很好,但这不适用于正确的插入。
    • 我已经更新了解决这个问题的答案。请立即检查。 -- 在第二个查询中添加 BEGIN EXCEPTION BLOCK
    猜你喜欢
    • 1970-01-01
    • 2022-07-28
    • 2021-05-22
    • 2013-03-11
    • 2013-02-12
    • 2015-12-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多