当前位置: 首页 > 面试题库 >

Oracle-创建触发器以更新另一个表时出现问题

祖新觉
2023-03-14
问题内容

我已经阅读了有关创建触发器的Oracle文档,并且正在按照显示的方式进行操作,但是这是行不通的。我的目标是使用出现在TPM_TRAININGPLAN表中的最小STARTDATE更新TPM_PROJECT表。因此,每次有人更新TPM_TRAININGPLAN中的STARTDATE列时,我都想更新TPM_PROJECT表。这是我正在尝试的方法:

CREATE TRIGGER Trigger_UpdateTrainingDelivery
    AFTER DELETE OR INSERT OR UPDATE OF STARTDATE
    ON TPM_TRAININGPLAN
    FOR EACH ROW WHEN (new.TRAININGPLANTYPE='prescribed')
    BEGIN
       UPDATE TPM_PROJECT SET TRAININGDELIVERYSTART = (SELECT MIN(TP.STARTDATE) FROM TPM_TRAININGPLAN TP WHERE TP.PROJECTID = new.PROJECTID AND TP.TRAININGPLANTYPE='prescribed')
       WHERE PROJECTID = new.PROJECTID
    END;

创建的触发器没有错误,但是我得到了警告:

 Warnings: ---> 
   W (1): Warning: execution completed with warning
          <---

当然,Oracle还不足以实际告诉我警告是什么,我只是被告知那里有一个警告。

接下来,如果我使用以下内容更新培训计划表:

UPDATE TPM_TRAININGPLAN
set STARTDATE = to_date('03/12/2009','mm/dd/yyyy')
where TRAININGPLANID=15916;

我收到错误消息:

>[Error] Script lines: 20-22 ------------------------
 ORA-04098: trigger 'TPMDBO.TRIGGER_UPDATETRAININGDELIVERY' is invalid and failed re-validation
 Script line 20, statement line 1, column 7

有什么想法我做错了吗?谢谢!


问题答案:

一些问题没有特别的顺序。

首先,在行级触发器的主体中,您需要使用:new:old引用新记录和旧记录。前导冒号是必要的。所以你的WHERE条款需要

WHERE PROJECTID = :new.PROJECTID

其次,如果您CREATE TRIGGER在SQL * Plus中运行,则可以使用以下SHOW ERRORS命令获得错误和警告的列表,即

SQL> show errors

您还可以查询DBA_ERRORS表(或ALL_ERRORSUSER_ERRORS根据您的权限级别),但是这不是你通常需要求助于。

第三,假设语法错误已得到纠正,如果使用此逻辑,您将得到一个变异表错误。表A的行级触发器(TPM_TRAININGPLAN在这种情况下)无法查询表A,因为表可能处于不一致状态。如Tim在他的文章中所示,您可以通过以下方法解决此问题:创建一个带有集合的程序包,在before语句触发器中初始化该集合,在行级触发器中填充集合中的数据,然后在其中处理修改后的行。一个after语句触发器。但是,由于要管理多个不同的对象,因此增加了相当多的复杂性。

通常,最好将这种逻辑实现为用于操作TPM_TRAININGPLAN表的任何API的一部分。如果这是一个存储过程,则将要更新的逻辑TPM_PROJECT放入该存储过程中而不是将其放入触发器中就更有意义了。众所周知,尝试调试在触发器中嵌入很多逻辑的应用程序是很痛苦的,因为这使开发人员很难完全了解正在执行的操作。或者,您可以TRAININGDELIVERYSTARTTPM_PROJECT表中删除该列,然后仅在运行时计算最小开始日期。

第四,如果触发器在插入,更新和删除时触发,则不能简单地引用:new值。 :new对插入和更新有效,但如果要删除,它将为NULL。
:old对删除和更新有效,但如果要执行插入操作,则将为NULL。这意味着您可能需要遵循以下逻辑(参考Tim的软件包解决方案

BEGIN
  IF inserting 
  THEN
    trigger_api.tab1_row_change(p_id => :new.projectid, p_action => 'INSERT');
  ELSIF updating
  THEN
    trigger_api.tab1_row_change(p_id => :new.projectid, p_action => 'UPDATE');
  ELSIF deleting
  THEN
    trigger_api.tab1_row_change(p_id => :old.projectid, p_action => 'DELETE');
  END IF;
END;


 类似资料:
  • 问题内容: 我有一个Maximo数据库,该数据库具有无法更改的表结构。我希望在创建或更新主电子邮件地址时将其复制到PERSON表中。以下结构描述了PERSON表和EMAIL表 PERSON表: EMAIL表: 如您所见,这两个表在PERSONID列上链接。这是我希望触发器执行的操作: 如果EMAIL表已更新或插入了新行,那么如果ISPRIMARY字段,我想将EMAILADDRESS字段复制到PER

  • userNotesTable: 用户提醒表: 插入触发器: 更新触发器: 这是数据库的当前代码,以及提醒表的特定触发器。我遇到的困难是,从提醒表中的specific中的user notes表中选择特定的名称和额外的内容,所有这些都在更新触发器中。 插入时,和会被插入到提醒和搜索表中,但我希望能够使用特定名称和用户注释表中的额外内容更新搜索表,这可能吗?

  • 问题内容: 我知道我可以使用它来创建DDL创建触发器; 问题在于,该触发器将在“创建序列”之类的DDL上运行;如何仅对“创建表” DDL执行此操作? 问题答案: CREATE OR REPLACE TRIGGER create_table_trigger AFTER CREATE ON SCHEMA BEGIN IF SYS.DICTIONARY_OBJ_TYPE = ‘TABLE’ THEN .

  • 问题内容: 我有一个触发器,我正尝试使用它来更新它侦听的同一张表。 但是,提交创建或更新后,出现以下错误: 感谢您的帮助! 问题答案: 您正在更新触发器已写入的同一表。您需要这样的东西:

  • 问题内容: 在oracle中,我可以指定列,这将引发触发器的触发: 现在,我想执行以下操作:当 只 更新 一 列时,我不希望触发触发器。这怎么可能? 我可以列出除那一列之外的所有列,该列不应引起触发器的触发。对于具有许多列的表而言,这非常麻烦。 另一种方法是使用像这样的UPDATING函数: 但是,如果我立即更改了COL1 和 COL3,则该语句的计算结果为false。那不是我想要的,因为我只想更

  • 问题内容: 我正在尝试编写触发器,我有下表:BookingRequest: 状态表: 被占领的房间: 我需要一个触发器,如果​​将具有相同ID的请求插入到OccupiedRoom表中,它将把BookingReques中的状态更改为1,所以我尝试了类似的操作 而且它不起作用,所以任何建议都非常有用 问题答案: 尝试这个: