首页 > 解决方案 > SQL 数据库触发器 ORA-00904

问题描述

如果预订评估编号为 2,我正在尝试将客户名称、开始日期和船名输入审核表。当我使用的名称在预订表中时,我收到无效标识符错误。现在,我只是想在审计表中获取客户名称,因此在其他列中为空。

这是我的代码,我看不到哪里出错了:

CREATE OR REPLACE TRIGGER EVALUATION
BEFORE INSERT OR UPDATE OR DELETE ON BOOKING
FOR EACH ROW 
WHEN (NEW.BOOKING_EVALUATION = 2)
DECLARE

custname  VARCHAR(20);
sdate    DATE;
shname   VARCHAR(50);

BEGIN

SELECT CUSTOMER_NAME INTO custname FROM customer WHERE CUSTOMER_NAME = NEW.CUSTOMER_NAME;


IF INSERTING THEN
INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
VALUES(:NEW.VOYAGES_ID,custname,NULL,NULL,:NEW.BOOKING_EVALUATION);
END IF;


IF UPDATING THEN
INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
VALUES(:OLD.VOYAGES_ID,custname,NULL,NULL,:OLD.BOOKING_EVALUATION);
END IF;


IF DELETING THEN
INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
VALUES(:OLD.VOYAGES_ID,custname,NULL,NULL,:OLD.BOOKING_EVALUATION);
END IF;
END;
/

这是我得到的错误:

9/1 PL/SQL:SQL 语句被忽略
9/67 PL/SQL:ORA-00904:“新”。“客户名称”:无效标识符

标签: oracleplsqldatabase-trigger

解决方案


您需要使用NEW伪记录中的字段,并且由于触发器所针对的表只有 ID,因此您需要使用它进行查找:

SELECT CUSTOMER_NAME
INTO custname
FROM customer
WHERE CUSTOMER_ID = :NEW.CUSTOMER_ID;

请注意 的:前缀NEW以及列/字段名称的更改。

IF DELETING不过,这对分支不太适用,因为NEW在这种情况下伪记录将为空 - 仅OLD填充。因此,您需要额外的逻辑来根据触发事件OLDNEW根据触发事件获取客户名称,并且根据您OLDUPDATING分支中使用的情况,您可能也需要旧客户 ID。

出于同样的原因,该WHEN (NEW.BOOKING_EVALUATION = 2)检查也不适用于删除。

所以你也许可以这样做:

CREATE OR REPLACE TRIGGER EVALUATION
BEFORE INSERT OR UPDATE OR DELETE ON BOOKING
FOR EACH ROW 
DECLARE

  custname  VARCHAR(20);

BEGIN

  IF INSERTING AND :NEW.BOOKING_EVALUATION = 2 THEN
    SELECT CUSTOMER_NAME
    INTO custname
    FROM customer
    WHERE CUSTOMER_ID = :NEW.CUSTOMER_ID;

    INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
    VALUES(:NEW.VOYAGES_ID,custname,NULL,NULL,:NEW.BOOKING_EVALUATION);
  END IF;

  IF (UPDATING OR DELETING) AND :OLD.BOOKING_EVALUATION = 2 THEN
    SELECT CUSTOMER_NAME
    INTO custname
    FROM customer
    WHERE CUSTOMER_ID = :OLD.CUSTOMER_ID;

    INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
    VALUES(:OLD.VOYAGES_ID,custname,NULL,NULL,:OLD.BOOKING_EVALUATION);
  END IF;
END;
/

取决于您是否要记录更新,如果旧的、新的或其中一个BOOKING_EVALUATION是 2。此版本仅查看您用于插入的其他值,但可以轻松检查其中一个,或者您可以OLD拆分又出来了UPDATING OR DELETING。或者您可以将第一个检查更改为:UPDATINGDELETING

...
BEGIN

  IF (INSERTING OR UPDATING) AND :NEW.BOOKING_EVALUATION = 2 THEN
...

这取决于您要捕获哪些场景以及要为它们记录哪些值。


如果您收到编译错误,则运行show errors或查询user_errors视图以查看实际故障。如果你得到 ORA-04098,那么错误所指的触发器是无效的——它要么是在它被编译的时候,要么是(我认为不太可能)表结构自上次成功编译以来发生了变化。

您可能已经创建了多个触发器。看看输出

select trigger_name, status from user_triggers where table_name = 'BOOKING';

查看该表有多少触发器(尽管它可能在其他地方)以及它们的名称 - 如果有多个触发器,请查看您是否有一个需要删除的不同名称的较早尝试。

看看

select object_name, status from user_objects where object_type = 'TRIGGER';

查看您定义的所有触发器并查找任何无效的触发器。user_triggers然后,如果从它们的名称中不明显,您可以返回视图以查看它们所针对的表。

但是,无论是无效的,原因都将在user_errors.


推荐阅读