如何获取更新行的主 ID 并在触发器中的 DML 之前使用它

How to get the main ID of updated row and use it before DML in trigger

我在开发 Oracle 触发器 (11g) 时受阻。触发器的目标是将一些数据存储在审计跟踪 table 中。此 table 中填充的字段之一是由包中的函数生成的 XML 块。 此函数有 1 个参数:要更新/删除的行的 ID。

所以我先写了这个触发器:

CREATE OR REPLACE TRIGGER TRG_TEMPLATE_FORMAT
BEFORE UPDATE OR DELETE
ON TEMPLATE_FORMAT
FOR EACH ROW

DECLARE
    v_TEMPLATE_XML          CLOB;  
    v_TEMPLATE_NAME         VARCHAR2(128);
    v_TEMPLATE_FULL_NAME    VARCHAR2(128);
BEGIN
    IF UPDATING THEN
        SELECT TEMPLATE_NAME INTO v_TEMPLATE_NAME FROM TEMPLATES WHERE TEMPLATE_ID =: OLD.TEMPLATE_ID;
        SELECT TEMPLATE_FULL_NAME INTO v_TEMPLATE_FULL_NAME FROM TEMPLATES WHERE TEMPLATE_ID = :OLD.TEMPLATE_ID;
        v_TEMPLATE_XML := PKG_TEMPLATE_MANAGEMENT.GET_TEMPLATE_XML(:OLD.TEMPLATE_ID);   
        INSERT INTO TEMPLATES_BACK(
            TEMPLATE_ID,
            TEMPLATE_FULL_NAME,
            TEMPLATE_NAME,
            EVENT_TYPE,
            EVENT_TIMESTAMP,
            OLD_XML_TEMPLATE_SOURCE        
        )
        VALUES(
            :OLD.TEMPLATE_ID,
            v_TEMPLATE_FULL_NAME,
            v_TEMPLATE_NAME,
            'UPDATE ON TEMPLATE_FORMAT',
            SYSDATE,
            v_TEMPLATE_XML
        );
    ELSIF DELETING THEN
        SELECT TEMPLATE_NAME INTO v_TEMPLATE_NAME FROM TEMPLATES WHERE TEMPLATE_ID = :OLD.TEMPLATE_ID;
        SELECT TEMPLATE_FULL_NAME INTO v_TEMPLATE_FULL_NAME FROM TEMPLATES WHERE TEMPLATE_ID = :OLD.TEMPLATE_ID;
        v_TEMPLATE_XML := PKG_TEMPLATE_MANAGEMENT.GET_TEMPLATE_XML(:OLD.TEMPLATE_ID);
        INSERT INTO TEMPLATES_BACK(
            TEMPLATE_ID,
            TEMPLATE_FULL_NAME,
            TEMPLATE_NAME,
            EVENT_TYPE,
            EVENT_TIMESTAMP,
            OLD_XML_TEMPLATE_SOURCE        
        )
        VALUES(
            :OLD.TEMPLATE_ID,
            v_TEMPLATE_FULL_NAME,
            v_TEMPLATE_NAME,
            'DELETE FROM TEMPLATE_FORMAT',
            SYSDATE,
            v_TEMPLATE_XML
        );
    END IF;
END;
/

由于 TEMPLATE_FORMAT table 在 GET_TEMPLATE_XML() 函数中使用,当然,我得到了旧的“good”“Table is mutating”错误...

我搜索了一下之后想到使用复合触发器,并在 BEFORE STATEMENT 块中调用我的函数。问题是 :OLD / :NEW 绑定,不能在那个块中使用

这个XML的最终目标是捕获几条记录的值,在这个XML任何修改之前,所以它可以很容易地回滚。

有没有其他方法我可能会错过处理这种情况?

提前致谢

通过在被调用函数 (PKG_TEMPLATE_MANAGEMENT.GET_TEMPLATE_XML) 中添加 pragma autonomous_transaction 解决。

再次感谢@ekochergin