如何在使用触发器插入之前成功引用另一个 table

How to successfully reference another table before insert with a trigger

我正在尝试创建一个触发器来验证 table registraties(注册)中的新条目是否包含有效的 MNR(员工编号),但我卡在了我引用 table medewerkers(员工)的部分。

有人可以帮我吗?

CREATE OR REPLACE TRIGGER t_MNRcontrole

BEFORE INSERT OR UPDATE 
ON registraties

DECLARE 
MNR_medewerkers number (SELECT MNR FROM MEDEWERKERS);

FOR EACH ROW
BEGIN 

IF :new.MNR <> MNR_medewerkers
THEN raise_application_error(-20111, 'Medewerker niet herkend!');

END IF;
END;

收到的错误消息是
ORA-24344: success with compilation error

MNR_medewerkers number (SELECT MNR FROM MEDEWERKERS);

总是会失败,因为它不是一个数字,除非你的 table 碰巧只有一个条目,即使那样我也不确定 PLSQL 是否允许它通过。

更标准的情况是首先声明数字,然后在代码块中执行 SELECT INTO 以及 WHERE 子句,确保仅从 table。然后你可以将这个数字与新数字进行比较。

但是,如果您不是要与某一特定行进行比较,而是要检查该条目是否存在于该 table 中。

BEGIN
  SELECT 1
    INTO m_variable
    FROM table
   WHERE MNR = :new.MNR;
EXCEPTION
  WHEN TOO_MANY_ROWS THEN
    m_variable = 1;
  WHEN OTHERS THEN
    m_variable = 0;
END;

预先声明m_variable,然后检查它是否为0然后报错。

too_many_rows 是为了防止 table 中有超过一行的 MNR,而 OTHERS 是为了 NO_DATA_FOUND,但我使用 OTHERS 来处理所有其他可能发生但可能不会发生的事情。

顺便说一句,这是要包含在主代码块中的代码块,因此在 BEGIN 和 IF 之间,只需更改 IF 以检查变量是否为 0。

PL/SQL 赋值运算符是 :=,或 select x into y from z 从 SQL 查询中填充。

FOR EACH ROW 是触发器规范的一部分,而不是 PL/SQL 代码。

如果 :new.mnr 不存在于父 table 中,您将得到一个 no_data_found 异常,而不是不匹配的变量。

错误消息最好包含失败的详细信息。

在编程中,我们使用缩进来表示代码结构。

固定版本应该是这样的:

create or replace trigger trg_mnrcontrole
    before insert or update on registraties
    for each row
declare
    mnr_medewerkers medewerkers.mnr%type;
begin
    select mw.mnr into mnr_medewerkers
    from   medewerkers mw
    where  mw.mnr = :new.mnr;

exception  
    when no_data_found then
        raise_application_error(-20111, 'Medewerker '||:new.mnr||' niet herkend!');
end;

但是,我们可以使用 foreign key constraint 更好地实现这种检查,例如:

alter table registraties add constraint registraties_mw_fk
foreign key (mnr) references medewerkers.mnr;