我是SQL的初学者,请耐心等待。
我正在尝试在SQL中创建一个触发器。这个代码给我带来了麻烦:
select brw.borage, bt.agelower, bt.ageupper
into borage, minage, maxage
from borrower brw
inner join loan ln on ln.borid = brw.borid
inner join bookcopy bc on ln.bcid = bc.bcid
inner join booktitle bt on bt.isbn = bc.isbn
where ln.bcid = :new.bcid
and ln.borid = :new.borid;
-- and ln.dateout = :new.dateout;
贷款表中的主键由"bcID"、"borID"one_answers"dateOut"组成。当我注释掉最后一行时,我会将新添加的行添加到表中。如果最后一行没有注释,它将不起作用!
我刚刚得到这个错误(没有注释行):
Row 34: ORA-01403: no data found
ORA-01403: no data found
这意味着oracle没有找到任何符合查询条件的行。
注意:当我取消对该行的注释时,我还会删除它上面的分号。
好。首先,表A
上的行级触发器不应查询表A
。一般来说,这样做会产生一个"ORA-04091:table is mutating"错误。由于触发器是在LOAN
上定义的,因此查询不应引用LOAN
表。它应该只引用:NEW
记录中当前行的数据。
在这种情况下,您可能想要这样的东西(注意,我猜测的是表之间关系的基数)
select brw.borage
into borage
from borrower brw
where brw.borid = :new.borid;
select bt.agelower, bt.ageupper
into minage, maxage
from bookcopy bc on :new.bcid = bc.bcid
inner join booktitle bt on bt.isbn = bc.isbn;
您可以将这两个查询组合在一起,但我认为没有一种简单的方法可以做到这一点,而不会使结果变得比您可能想要的更复杂。
此外,您确实希望避免在数据库中使用共享列名称的局部变量(如borage
)。这往往会产生相当令人困惑的范围解析错误。例如,使用SCOTT.EMP
表
没有EMPNO
为-17 的员工
SQL> select count(*)
2 from emp
3 where empno = -17;
COUNT(*)
----------
0
但是,当我编写一个简单的PL/SQL块,试图计算EMPNO
为-17的员工数量时,得到的结果是14。你能发现虫子吗?
SQL> ed
Wrote file afiedt.buf
1 declare
2 empno integer := -17;
3 cnt integer;
4 begin
5 select count(*)
6 into cnt
7 from emp e
8 where e.empno = empno;
9 dbms_output.put_line( cnt );
10* end;
SQL> /
14
PL/SQL procedure successfully completed.
问题是,当我编写e.empno = empno
时,我清楚地希望表达式的左侧引用EMP
表中的EMPNO
列,而表达式的右侧引用局部变量EMPNO
。然而,对我来说不幸的是,Oracle首先将不合格的EMPNO
解析为表中的一列,然后才将其解析为同名的局部变量。如果您使用的是命名的PL/SQL块,您可以通过使用块的名称作为局部变量的别名来解决这个问题,但实际上从来没有人这样做过。
相反,为了避免这类问题,大多数开发人员会为变量名使用某种独特的前缀。例如,我将P_
用作参数名称的前缀,将L_
用作局部变量的前缀,并将G_
用作包全局变量的前缀。这是一个相对常见的惯例,但也存在其他惯例。重要的是要有某种方法来确保局部变量和列名永远不会使用相同的名称。
如果您需要忽略此错误并继续执行触发器,您可以添加
exception
WHEN NO_DATA_FOUND THEN
NULL
所以你的扳机看起来像
begin
select brw.borage, bt.agelower, bt.ageupper
into borage, minage, maxage
from borrower brw
inner join loan ln on ln.borid = brw.borid
inner join bookcopy bc on ln.bcid = bc.bcid
inner join booktitle bt on bt.isbn = bc.isbn
where ln.bcid = :new.bcid
and ln.borid = :new.borid;
and ln.dateout = :new.dateout;
// other actions
exception
WHEN NO_DATA_FOUND THEN
NULL
end;