将日期与 SQL 中的":new"表进行比较



我是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;

最新更新