为啥我的 PL/SQL 触发器会引发“错误(2,2):PL/SQL:语句被忽略”和“错误(2,5):PLS-00204:函数或伪列'EXISTS'”错误?

Posted

技术标签:

【中文标题】为啥我的 PL/SQL 触发器会引发“错误(2,2):PL/SQL:语句被忽略”和“错误(2,5):PLS-00204:函数或伪列\'EXISTS\'”错误?【英文标题】:Why is my PL/SQL trigger raising an "Error(2,2): PL/SQL: Statement ignored" and an "Error(2,5): PLS-00204: function or pseudo-column 'EXISTS' " error?为什么我的 PL/SQL 触发器会引发“错误(2,2):PL/SQL:语句被忽略”和“错误(2,5):PLS-00204:函数或伪列'EXISTS'”错误? 【发布时间】:2016-04-05 07:39:29 【问题描述】:

我正在尝试编写一个触发器,如果​​学生已经在上他们试图成为助教的课程,该触发器会阻止插入到我的助教(助教)表中。据我了解,最好的方法(除了唯一约束,这必须是触发器)是通过使用回滚,我也在使用 raiserror。

create or replace trigger CheckTA
after insert
on TA for each row
begin
if exists (select * from Enrolls where Student_ID = :new.Student_ID and Course_ID = :new.Course_ID) then
rollback;
raiserror('TA enrolled in course as student');
end if;
end;

在创建触发器时,我遇到了以下错误:

错误(2,2):PL/SQL:语句被忽略

错误(2,5):PLS-00204:函数或伪列“EXISTS”只能在 SQL 语句中使用

触发器仍然会被创建,但是当不正确的值被插入到 TA 中时它不会触发。

表格:TA

Create table TA
(
Student_ID int references Student(Student_ID),
Course_ID int references Course(Course_ID),
Courses_taught varchar2(250),
Office_hours varchar2(25)
);

学生

create table Student
(
Student_ID int primary key,
Name varchar2(50),
Start_began int,
Semester_began varchar2(50),
GPA int,
Degree_status varchar2(25),
Degree_type varchar2(50),
Courses_Taken varchar2(250),
JI_list varchar2(250),
Profile_status varchar2(50)
);

课程

create table Course
(
Course_ID int primary key,
Course_Name varchar2(25)
);

注册

create table Enrolls
(
Student_ID int references Student(Student_ID),
Course_ID int references Course(Course_ID)
);

存储过程 这是我用来插入应该触发触发器的 TA 值的 SP。它不会引发错误,但我会把它放在这里以防万一。

create or replace procedure addTA (s_id int, c_id int, course varchar2)
as
begin
insert into TA (Student_ID,Course_ID,Courses_taught)
values (s_id,c_id,course);
end;

老实说,我不太确定这些错误是什么意思,更不用说是什么导致了它们,但我仍然尝试弄乱 raiserror 的语法,并用 raise_application_error 替换它,但没有运气。如果有人可以帮助我解决或至少解释这些错误,将不胜感激。当然,如果我的触发器有任何明显错误,请告诉我。

【问题讨论】:

使用触发器强制执行此类业务约束通常是一个坏主意,因为它们在多用户场景中往往会失败。想想如果第二个会话向enrolls 表添加一行,但仅在第一个会话向TA 表添加一行后才提交,会发生什么情况。一个适当的唯一约束是要走的路(你已经提到这是一种替代方法,顺便说一句)。 【参考方案1】:

错误提示“函数或伪列 'EXISTS' 只能在 SQL 语句中使用”,这意味着您只能在 SQL 语句中使用 EXISTS,而在 PL/SQL 语句中使用 in .

如果你需要检查一些记录是否存在,你可以试试这样:

vNum number;
...
select count(1)
into vNumber
from Enrolls
where Student_ID = ...

if vNumber > 0 then
    ...
else
    ...
end if;

【讨论】:

以上是关于为啥我的 PL/SQL 触发器会引发“错误(2,2):PL/SQL:语句被忽略”和“错误(2,5):PLS-00204:函数或伪列'EXISTS'”错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在匿名 PL/SQL 块中没有立即引发异常?

引发异常后 PL/SQL 继续

为啥不允许在 PL/SQL 触发器中使用 ROLLBACK 语句,但 RAISE_APPLICATION_ERROR 是?

为啥 oracle 中的应用程序上下文使用 PL/SQL 过程

为啥在 PL/SQL Oracle 中尝试创建 INSTEAD OF 触发器时出现“错误的绑定变量”错误?

为啥 PL/SQL 会失败