我是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”和“dateOut”组成。 当我注释掉最后一行时,我将新添加的行添加到表中。 虽然最后一行没有注释,但它不起作用!
我刚收到此错误(取消注释该行):
Row 34: ORA-01403: no data found
ORA-01403: no data found
意味着oracle没有找到符合查询条件的任何行。
注意:当我取消注释该行时,我也会删除其上方的分号。
答案 0 :(得分:4)
行。首先,表A
上的行级触发器不应查询表A
。一般来说,这样做会产生一个" ORA-04091:表正在变异"错误。由于您的触发器是在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块试图计算{-1}}为-17的员工数时,我得到的结果是14.你能发现这个错误吗?
EMPNO
问题在于,当我写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
表和右侧的EMPNO
列表达式引用局部变量EMP
。不过对我来说不幸的是,Oracle首先将非限定EMPNO
解析为表中的一列,然后再解析为同名的局部变量。如果你正在使用命名的PL / SQL块,你可以通过使用块的名称作为局部变量的别名来解决这个问题,但几乎没有人这样做过。
相反,为了避免这些问题,大多数开发人员会为变量名使用某种独特的前缀。例如,我使用EMPNO
作为参数名称的前缀,P_
作为局部变量的前缀,L_
作为包全局变量的前缀。这是一个相对常见的惯例,但存在其他惯例。重要的是要有一些方法来确保你永远不会有一个使用相同名称的局部变量和列名。
答案 1 :(得分:0)
如果您需要忽略此错误并继续执行触发器,则只需添加
即可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;