已创建触发器但无法检测到更新

Created triggers but not able to detect the update

您好,我正在尝试创建审核 table,它将在触发器 table 发生变化时插入行 table。

触发:

create or replace TRIGGER ABC
AFTER
  UPDATE ON TABLE1
  FOR EACH ROW DECLARE 
  DB_USER VARCHAR2(100);
  OS_USER    VARCHAR2(100);
  IP_ADDRESS VARCHAR2(100);
  BEGIN
    SELECT USER INTO DB_USER FROM DUAL;
    SELECT SYS_CONTEXT('USERENV', 'OS_USER') INTO OS_USER FROM DUAL;
    SELECT SYS_CONTEXT('USERENV','IP_ADDRESS')INTO IP_ADDRESS FROM DUAL;
    IF UPDATING('NAME'|| 

    'NOTES' ) THEN

   ABC_PROC(:NEW.ID,:OLD.NAME,:NEW.NAME,:OLD.NOTES ,:NEW.NOTES 
 ,DB_USER, OS_USER,IP_ADDRESS);

   END IF;
  END;

程序:

create or replace PROCEDURE ABC_PROC

  ( 
  ID IN NUMBER,
  OLD_NAME IN VARCHAR2,
  NEW_NAME IN VARCHAR2,
  OLD_NOTES IN VARCHAR2,
  NEW_NOTES IN VARCHAR2,
    DB_USER IN VARCHAR2,
    OS_USER IN VARCHAR2,
    IP_ADDRESS IN VARCHAR2
   ) AS
BEGIN

    IF ( OLD_NAME!= NEW_NAME )  or

        ( OLD_NOTES  != NEW_NOTES ) 
         THEN

  INSERT INTO "AUDIT_TABLE"(
    ID,
        OLD_NAME ,NEW_NAME ,

  OLD_NOTES ,NEW_NOTES ,
DBUSER,OSUSER,IP_ADDRESS)
VALUES
(
 ID,
        OLD_NAME ,NEW_NAME ,
  OLD_NOTES ,NEW_NOTES,
DB_USER, OS_USER,IP_ADDRESS
);
  END IF;

Exception
        when VALUE_ERROR then
            DBMS_OUTPUT.PUT_LINE('VALUE ERROR');
       WHEN OTHERS THEN
          DBMS_OUTPUT.PUT_LINE('OTHERS SQLCODE:'||SQLCODE||', SQLERRM:'||SQLERRM);

END ABC_PROC;

AUDIT_TABLE:

  CREATE TABLE "XCHANGE"."AUDIT_TABLE" 
   (    "ID" NUMBER(19,0) NOT NULL ENABLE, 
    "OLD_NAME" VARCHAR2(100 BYTE), 
    "NEW_NAME" VARCHAR2(100 BYTE), 
    "OLD_NOTES" VARCHAR2(100 BYTE), 
    "NEW_NOTES" VARCHAR2(100 BYTE), 
    "DBUSER" VARCHAR2(100 BYTE), 
    "OSUSER" VARCHAR2(100 BYTE), 
    "IP_ADDRESS" VARCHAR2(100 BYTE)
   ) SEGMENT CREATION IMMEDIATE 
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 
 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS" ;

审核 table、触发器和过程都已成功创建,但是当我更新 table 时,它无法插入更改。

您的触发器包括:

IF UPDATING('NAME'|| 'NOTES') THEN

在 Oracle(和大多数 SQL)中,|| 是连接运算符,而不是逻辑的 OR。因此,只有在更新名为 NAMENOTES 的列时才会发生插入,而不是在更新名为 NAME 的名为 [=17] 的列时发生=],正如你想的那样。

改为:

IF UPDATING('NAME') OR UPDATING('NOTES') THEN

顺便说一句,局部变量似乎没有多大意义,您可以直接将 USERSYS_CONTEXT('USERENV', 'OS_USER') 等传递到过程调用中。无需从双重选择。


如果您希望审计记录只显示实际更改的值,则需要在值子句中添加一些逻辑,您可以使用 case 表达式来实现。我建议您更改过程参数名称,使它们与列名称不匹配以避免混淆,例如带有 P_ 前缀(尽管有些人更喜欢直接使用 table/procedure 名称来标识每个名称的来源):

CREATE OR REPLACE PROCEDURE ABC_PROC ( 
  P_ID IN AUDIT_TABLE.ID%TYPE,
  P_OLD_NAME IN AUDIT_TABLE.OLD_NAME%TYPE,
  P_NEW_NAME IN AUDIT_TABLE.NEW_NAME%TYPE,
  P_OLD_NOTES IN AUDIT_TABLE.OLD_NOTES%TYPE,
  P_NEW_NOTES IN AUDIT_TABLE.NEW_NOTES%TYPE,
  P_DB_USER IN AUDIT_TABLE.DB_USER%TYPE,
  P_OS_USER IN AUDIT_TABLE.OS_USER%TYPE,
  P_IP_ADDRESS IN AUDIT_TABLE.IP_ADDRESS%TYPE
) AS
BEGIN
  IF (P_OLD_NAME != p_NEW_NAME) or (P_OLD_NOTES != P_NEW_NOTES) THEN
    INSERT INTO AUDIT_TABLE (ID, OLD_NAME, NEW_NAME, OLD_NOTES, NEW_NOTES,
      DBUSER, OSUSER, IP_ADDRESS)
    VALUES (P_ID,
      CASE WHEN P_OLD_NAME != P_NEW_NAME THEN P_OLD_NAME END,
      CASE WHEN P_OLD_NAME != P_NEW_NAME THEN P_NEW_NAME END,
      CASE WHEN P_OLD_NOTES != P_NEW_NOTES THEN P_OLD_NOTES END,
      CASE WHEN P_OLD_NOTES != P_NEW_NOTES THEN P_NEW_NOTES END,
      P_DB_USER, P_OS_USER, P_IP_ADDRESS);
  END IF;
END ABC_PROC;

只有当执行更新的客户端恰好启用了输出时,您的异常处理程序才会显示任何内容,这是您不能依赖的; squashing/hiding 任何错误,尤其是 when others,真的不是一个好主意。有一天您会发现您没有审计记录,但不知道为什么。

虽然我完全不确定为什么要在此处设置过程,但直接从触发器执行插入会更简单。如果您也计划在其他地方调用过程表单 - 无法想象为什么 - 您可以在过程中获取用户和上下文值,而不是传递它们。您拥有的比较逻辑也不会捕捉到值从 null 变为非 null,反之亦然,但它们可能是主 table 中的非空列。