Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 已创建触发器,但无法检测更新_Sql_Oracle_Triggers_Procedure - Fatal编程技术网

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

Sql 已创建触发器,但无法检测更新,sql,oracle,triggers,procedure,Sql,Oracle,Triggers,Procedure,您好,我正在尝试创建审计表,该表将在触发器表中更改行时插入该行 触发器: 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; S

您好,我正在尝试创建审计表,该表将在触发器表中更改行时插入该行

触发器:

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;
程序:

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;
审计表:

  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" ;

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

您的触发器包括:

IF UPDATING('NAME'|| 'NOTES') THEN
在Oracle(和大多数SQL)中,
|
是串联运算符,而不是逻辑的
。因此,只有在更新名为
NAMENOTES
的列时,插入才会发生,而不是在更新名为
NAME
的列或名为
NOTES
的列时,插入才会发生

相反,你应该:

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

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


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

只有在执行更新的客户机恰好启用了输出时,异常处理程序才会显示任何内容,这是您无法依赖的;而且挤压/隐藏任何错误,尤其是当其他错误发生时,确实不是一个好主意。有一天你会意识到你没有审计记录,但不知道为什么


我不知道为什么这里有一个过程,但是直接从触发器插入会更简单。如果您计划在其他地方调用过程表单(无法想象为什么),您可以在过程中获取用户和上下文值,而不是传递它们。您拥有的比较逻辑也不会捕获从null到非null的值,反之亦然,但它们在主表中可能不是null列。

您是否收到任何错误消息?运行update语句时,您可能需要“将serveroutput设置为打开”,以便在异常句柄中查看DBMS|U output语句生成的输出您希望
更新('NAME'| |'NOTES')
做什么?语法是
更新(“”)
。我不知道你打算做什么。也许您想完全删除
IF
语句。也许您有一个更深层次的问题……您好,Alex Poole,它能够检测到更改,但现在的问题是:在过程中,我给出了一个条件,如果(OLD_NAME!=NEW_NAME)或(OLD_NOTES!=NEW_NOTES),然后插入“AUDIT_TABLE”(ID、旧\u名称、新\u名称、旧\u注释、新\u注释、DBUSER、OSUSER、IP\u地址)值(ID、旧\u名称、新\u名称、旧\u注释、新\u注释、DB\u用户、OS\u用户、IP\u地址);END IF;此条件不起作用。它将转储所有两列而不是一列。@user3352615-抱歉,我不确定您的意思。如果任一列的值都已更改,则它将同时记录这两个列。这是您要求它执行的操作。不过,您不允许为null。(过程的参数名与列名相同会让人困惑)我想知道中的一列是否已更改。它应该将一列的值显示为已更改,而将其他列的值显示为null null。例如:假设在开始时名称为“test”,更新后描述为“new”,则名称为“test2”,描述为“new”。在此之后,我的审核表应该显示这些结果是old_name='test',new_name='test2',old_description=null和new_description='null'。期待听到答案,谢谢。@user3352615-这确实偏离了您的原始问题,但不确定是否值得单独提问。我已经在您的过程中添加了一个变体和一些其他注释。如果您有进一步的问题,请你应该问一个新问题。