SQL错误:执行触发时ORA-04091

时间:2017-07-11 11:29:40

标签: oracle plsql triggers

我正在尝试执行我的触发器:

CREATE OR REPLACE TRIGGER Trg_video_bfr_delete
    AFTER DELETE ON CMS_VIDEO
    FOR EACH ROW
DECLARE
    CODE varchar2(60);   
BEGIN
    SELECT CODE INTO CODE 
    from CMS_VIDEO 
    WHERE CODE = :OLD.CODE;
    IF CODE IS NOT NULL THEN
        INSERT INTO ASSET_DELETE_INDEX(CODE,ASSET_TYPE,IW_VPATH,LANGUAGE,MODIFIED_DTE) 
        VALUES (CODE,'Video',:old.IW_VPATH,:old.CONTENT_LANGUAGE,sysdate);
    END IF;
EXCEPTION 
    WHEN NO_DATA_FOUND THEN
        INSERT INTO ASSET_DELETE_INDEX (CODE,ASSET_TYPE,IW_VPATH,LANGUAGE,MODIFIED_DTE)
        VALUES (CODE,'Video',null,:old.CONTENT_LANGUAGE,sysdate);
        COMMIT;
END Trg_video_bfr_delete;
/

但是我在表上执行删除命令时遇到以下错误

错误报告 -

  

SQL错误:ORA-04091:表LSDS.CMS_VIDEO正在变异,触发/功能可能看不到它
  ORA-06512:在“LSDS.TRG_VIDEO_BFR_DELETE”,第6行   ORA-04088:执行触发器'LSDS.TRG_VIDEO_BFR_DELETE'时发生错误   04091. 00000 - “表%s。%s正在变异,触发/功能可能看不到它”
  *原因:触发器(或用户定义的plsql函数,在              这句话)试图查看(或修改)一个表格              在被解雇它的声明修改的中间   *操作:重写触发器(或函数),使其不读取该表。

有人可以帮忙吗?

3 个答案:

答案 0 :(得分:2)

您已写入触发器AFTER DELETE ON CMS_VIDEO。从DELETE表执行CMS_VIDEO时,将触发此触发器。因此,在修改CMS_VIDEO表时,您无法在任何触发器,过程或函数中修改或查询同一个表。

CREATE OR REPLACE TRIGGER Trg_video_bfr_delete
AFTER DELETE ON CMS_VIDEO
FOR EACH ROW

BEGIN
  IF :old.CODE IS NOT NULL THEN
    INSERT INTO ASSET_DELETE_INDEX(CODE, ASSET_TYPE, IW_VPATH, LANGUAGE, MODIFIED_DTE)
    VALUES (:old.CODE, 'Video', :old.IW_VPATH, :old.CONTENT_LANGUAGE, sysdate);
  END IF;
END Trg_video_bfr_delete;
/

答案 1 :(得分:0)

这是因为您正在从表中删除记录,同一个表用作触发器内的引用。这是" Mutating Error"的情况。您应该切换到语句级触发器它是否符合您的要求,或者您可以使用具有多个入口点且能够处理此类场景的复合触发器。

请参阅https://oracle-base.com/articles/9i/mutating-table-exceptions

答案 2 :(得分:-1)

根据提供的代码段,我在SELECT变异TABLE时没有看到任何意义。 我们可以轻松地 :OLD.CODE 来获取值。希望在片段下方有所帮助。

CREATE OR REPLACE TRIGGER Trg_video_bfr_delete AFTER
  DELETE ON CMS_VIDEO FOR EACH ROW 
--  DECLARE CODE VARCHAR2(60);
  BEGIN
--    SELECT CODE INTO CODE FROM CMS_VIDEO WHERE CODE = :OLD.CODE;
    IF CODE IS NOT NULL THEN
      INSERT
      INTO ASSET_DELETE_INDEX
        (
          CODE,
          ASSET_TYPE,
          IW_VPATH,
          LANGUAGE,
          MODIFIED_DTE
        )
        VALUES
        (
          :old.code,
          'Video',
          :old.IW_VPATH,
          :old.CONTENT_LANGUAGE,
          sysdate
        );
    END IF;
  EXCEPTION
  WHEN OTHERS THEN
    INSERT
    INTO ASSET_DELETE_INDEX
      (
        CODE,
        ASSET_TYPE,
        IW_VPATH,
        LANGUAGE,
        MODIFIED_DTE
      )
      VALUES
      (
        :old.code,
        'Video',
        NULL,
        :old.CONTENT_LANGUAGE,
        sysdate
      );
    COMMIT;
  END Trg_video_bfr_delete;