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-这确实偏离了您的原始问题,但不确定是否值得单独提问。我已经在您的过程中添加了一个变体和一些其他注释。如果您有进一步的问题,请你应该问一个新问题。