【问题标题】:SQL Database trigger ORA-00904SQL 数据库触发器 ORA-00904
【发布时间】:2018-07-03 23:52:09
【问题描述】:

如果预订评估编号为 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:“新”。“客户名称”:无效标识符

【问题讨论】:

  • BOOKING表中有CUSTOMER_NAME列吗?
  • 不,它在客户表中,我在预订表中没有客户名称。
  • 那么您不能在BOOKING 的触发器中使用NEW.CUSTOMER_NAME。 (即使您将缺少的 : 放在它前面。)
  • 我在预订表中有客户ID,但是当预订评估为2时,我需要将客户表中的客户名称添加到审计表中。
  • 然后将获取客户名称的查询更改为使用 ID。

标签: oracle plsql database-trigger


【解决方案1】:

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

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

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

这对IF DELETING 分支不太适用,因为在这种情况下NEW 伪记录将为空 - 只有OLD 被填充。因此,您需要额外的逻辑来获取基于OLDNEW 的客户名称,具体取决于触发事件,并且基于您在UPDATING 分支中使用OLD,您可能也需要旧客户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。此版本仅在 UPDATING OR DELETING 中查看 OLD,因为这些是您用于插入,但可以轻松检查,或者您可以再次拆分 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 中可见。

【讨论】:

  • 尝试更新预订表时,我收到一条错误消息:SQL> UPDATE BOOKING 2 SET BOOKING_EVALUATION = 2 3 WHERE BOOKING_ID = 1421;更新预订 * 第 1 行出现错误:ORA-04098:触发器“OPS$1319260.EVALUATION_TRIGGER”无效且重新验证失败 触发器创建时没有错误
  • @Moraqib - 是这个触发器(在问题和我的答案中称为EVALUATION);或者您是否在此表上创建了两个具有不同名称的触发器?查看user_triggers 以检查table_name='BOOKING 的实际存在,如果您有多个丢弃任何您实际上不需要的。然后如果剩下的内容无效,请查询user_errors 了解原因。
  • 它是答案中的触发器,触发器创建没有错误,但是当我尝试更新预订表时,我得到了错误。
  • 但是消息里的名字不一样?你在user_errors 看到了什么?
  • 答案中的触发器,我使用触发器创建的触发器没有问题,它只是在我更新错误时发生。这是 select * from user_errors 的输出:
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-12
相关资源
最近更新 更多