Reputation: 119
Hi I am trying to create audit table which will insert the row when their is change in the trigger table.
TRIGGER:
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;
PROCEDURE:
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" ;
Audit table , Trigger and Procedure all are created successfully but when i am updating the table it is not able to insert the change.
Upvotes: 0
Views: 77
Reputation: 191235
Your trigger includes this:
IF UPDATING('NAME'|| 'NOTES') THEN
In Oracle (and most SQL) the ||
is the concatenation operator, not the logical OR
. So your insert would only happen if you were updating a column called NAMENOTES
, rather than if you were updating a column called NAME
or a column called NOTES
, as you presumably intended.
Instead do:
IF UPDATING('NAME') OR UPDATING('NOTES') THEN
Incidentally, there doesn't seem much point having the local variables, you can just pass USER
, SYS_CONTEXT('USERENV', 'OS_USER')
etc. directly into the procedure call. No need to have the selects from dual.
If you want your audit record to only show the values that actually changed, you need some logic in the values clause, which you can do with a case expression. I'd recommend you change your procedure parameter names so they don't match the column names to avoid confusion, e.g. with a P_
prefix (though some people prefer to just explicitly use the table/procedure name to identify where each is coming from instead):
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;
Your exception handlers will only show anything if the client that does the update happens to have output enabled, which you can't rely on; and squashing/hiding any errors, especially when others
, really isn't a good idea. You'll realise one day you don't have audit records but have no idea why.
I'm not sure why you have a procedure here at all though, it would be simpler to just do the insert directly from the trigger. If you plan to call the procedure form somewhere else too - can't imagine why - you could get the user and context values within the procedure rather than passing them around. The comparison logic you have also won't catch a value changing from null to non-null, or vice versa, but they may be not-null columns in the main table anyway.
Upvotes: 2