我在模式 MARSEL 上有一个表 Uspev,其中包含学生(学生 ID)、predmet(科目 ID)、ocenka(分数)和数据(考试日期)列。我需要编写一个复合触发器,禁止学生每天参加两次以上考试(不关心哪一场考试,只关心参加考试的事实)。教授提供了一个触发器的例子,但它导致了“mutating-table”错误。 至于我的代码,在 before 语句之前声明了变量,即记录数组和计数器。虽然计数器没有以红色突出显示,但 SELECT COUNT(*) 中使用的数组却以红色突出显示。我按照手册'https://docs.oracle.com/en/database/oracle//oracle-database/21/lnpls/database-pl-sql-language-reference.pdf'编写的,但它没有似乎有效。这是我的代码:
CREATE OR REPLACE TRIGGER MARSEL.STUD_USPEV
FOR UPDATE OF DATA ON MARSEL.USPEV
COMPOUND TRIGGER
TYPE r_student_exam_date_type IS RECORD ( //a record type to hold a student ID
stud MARSEL.USPEV.STUDENT%TYPE, //and their exam date
exam_date MARSEL.USPEV.DATA%TYPE
);
TYPE t_student_exam_date_type IS TABLE OF r_student_exam_date_type //array type containing the records
INDEX BY PLS_INTEGER;
t_student_exam_date t_student_exam_date_type; //the array declaration
counter number; //the counter will count how many exams a student have sat during a day being inserted
BEFORE STATEMENT IS
BEGIN
SELECT r_student_exam_date_type // inserting all rows into the array
BULK COLLECT INTO t_student_exam_date
FROM MARSEL.USPEV;
END BEFORE STATEMENT;
AFTER EACH ROW IS
BEGIN
counter := 0;
SELECT COUNT(*) INTO counter //counting existing dates with the same student ID as the one being inserted
FROM t_student_exam_date //HIGHLIGHTED AS UNDEFINED
WHERE stud = :NEW.student AND exam_date = :NEW.data;
IF (counter > 1)
THEN Raise_Application_Error(-20000, 'a student cannot sit more than two exams a day');
END IF;
END AFTER EACH ROW;
END STUD_USPEV;
不能在 SQL 查询中使用本地声明的集合类型;即使您执行了
TABLE(t_student_exam_data)
并删除了 INDEX BY
子句,您也会收到 ORA-22905: 无法访问非嵌套表项中的行。集合类型需要在架构级别创建或在包规范中声明才能在查询中使用。
您可以改为循环遍历集合,并为每个匹配记录增加计数器:
AFTER EACH ROW IS
BEGIN
counter := 0;
FOR i IN 1..t_student_exam_date.count
LOOP
IF t_student_exam_date(i).stud = :NEW.student
AND t_student_exam_date(i).exam_date = :NEW.data
THEN
counter := counter + 1;
END IF;
END LOOP;
IF counter > 1
THEN
Raise_Application_Error(-20000, 'a student cannot sit more than two exams a day');
END IF;
END AFTER EACH ROW;
你的批量收集也是错误的,但可能是在发布时更改错误;并且您添加的评论是非法的。您需要将触发器设置为
FOR INSERT OR UPDATE
更改后,它现在可以工作了。
您可能想查看边缘情况,例如将行更新为同一日期...