Как исправить код для триггера, который предотвращает вставку на основе некоторых условий - PullRequest
0 голосов
/ 23 октября 2019

Я пытаюсь создать триггер, с которым у меня проблемы. Работа триггеров - остановить вставку элемента. Здесь есть 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;
/

Я должен проверить и запретить вставку, когда студент не зачислен на этот предмет, и если он у него есть, он начнет его со следующего семестра, поэтому в настоящее время он там не зачислен. .

Пожалуйста, помогите мне с этим.

Ответы [ 2 ]

0 голосов
/ 23 октября 2019

Ваш код довольно неясен, поэтому я просто использую те же условия, которые использовались вами в вашем вопросе, чтобы сообщить вам, как действовать.

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;
/

Приветствия !!

0 голосов
/ 23 октября 2019

Вероятно, у вас есть проблемы с логическим приоритетом в ваших условиях, поскольку он содержит AND s и OR s без скобок. Кроме того, вы проверяете скалярные значения для подзапросов, которые возвращают более одной строки или более одного столбца, это приведет к ошибкам во время выполнения.

Но в целом, я думаю, что ваш код можно упростить с помощью уникального 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 вместо).

...