I'm going to create a trigger to audit a table. Suppose my table define as below.
COUNTRY_ID NOT NULL CHAR(2)
COUNTRY_NAME VARCHAR2(40)
REGION_ID NUMBER
and my log table created as below.
create table country_log(
username varchar2(10),
transaction_date date,
new_value varchar(20),
old_value varchar(20)
)
My half completed trigger would be like below.
CREATE OR REPLACE TRIGGER tr_countryTable
AFTER UPDATE ON COUNTRIES
FOR EACH ROW
BEGIN
insert into country_log (username,transaction_date,new_value,old_value ) values (USER, sysdate,**:New, :Old** );
END;
/
I need to know instead of comparing each column value in :old and :new, how to get exactly updated column's new and old values.
In an UPDATE trigger, a column name can be specified with an UPDATING predicate to determine if the named column is being updated. Let's define a trigger as the following:
CREATE OR REPLACE TRIGGER tr_countryTable
AFTER UPDATE ON COUNTRIES
FOR EACH ROW
BEGIN
IF UPDATING ('COUNTRY_NAME') THEN
-- :new.COUNTRY_NAME is new value
-- :old.COUNTRY_NAME is old value
END IF;
IF UPDATING ('REGION_ID') THEN
-- :new.REGION_ID is new value
-- :old.REGION_ID is old value
END IF;
END;
/
Oracle 11g triggers documentation
Related
create trigger calculation after insert on employee
for each row
begin
if :new.updated_sal is null
then
update employee set updated_sal= (10/100)* salary
where id=:new.id;
end if;
end;
I would like to create a trigger on the employee table, whenever a new record is inserted in the same table, a 10% of salary in the salary column should be calculated and put into another column updated_sal.
If I try to insert a new record, it is showing that the table is mutated, etc
It's just the :new pseudorecord you need:
create trigger calculation
after insert on employee
for each row
begin
if :new.updated_sal is null then
:new.updated_sal := (10/100) * :new.salary;
end if;
end;
You need to use before insert trigger,
And use :New.updated_sal:= :new.salary * somevalue
To assign salary.
Following is a dummy table on which i am performing some updations. Here, i am only manipulating the "NAME" column. What i need is to insert the affected row, (say) i change the second for for "ID"-2, then i need that only this row should get inserted in a new table with new / updated value. I have tried doing so via a trigger but it vomits an error regarding table mutation.
ID NAME
================
1 Vaz
2 Dan
3 Steve
The table i want the data to get inserted has the same structure as the above mentioned table and same columns with same datatype.
Please suggest if this could be done in any other way or I am writing wrong code for the trigger. Here is the code i wrote for the purpose :
CREATE OR REPLACE TRIGGER HR.ins_temp
after UPDATE OF name ON HR.TEMP2 FOR EACH ROW
BEGIN
INSERT INTO temp3
(SELECT NAME
FROM temp2
WHERE (:new.NAME<>:old.NAME));
END;
temp2 is the manipulation tabel and temp3 is the new one.
No need for a SELECT. And you probably also want to put the ID value into the table temp3
CREATE OR REPLACE TRIGGER HR.ins_temp
after UPDATE OF name ON HR.TEMP2 FOR EACH ROW
BEGIN
INSERT INTO temp3 (id, name)
values (:new.id, :new.name);
END;
/
And as the trigger is defined as update of name you don't really need to check if the name changed, but if you want, you can do:
CREATE OR REPLACE TRIGGER HR.ins_temp
after UPDATE OF name ON HR.TEMP2 FOR EACH ROW
BEGIN
if ( (:new.name <> :old.name)
OR (:new.name is null and :old.name is not null)
OR (:new.name is not null and :old.name is null))
then
INSERT INTO temp3 (id, name)
values (:new.id, :new.name);
end if;
END;
/
I have the following existing trigger on the PERSON table in my WORKPLACE schema.
Currently, It updates the last_updated column automatically to the current date when any other column is altered.
Trigger:
CREATE OR REPLACE TRIGGER "WORKPLACE"."UPD_PERSON"
BEFORE update ON person
FOR each row
BEGIN
:new.last_updated := systimestamp;
END;
Current table:
ID | Name | Created | last_updated | checked
I have a column within my table named 'checked' , how can I changed this trigger so that when the 'checked' column is changed, that the last_updated column is NOT changed.
From the documentation:
"An UPDATE statement might include a list of columns. If a triggering statement includes a column list, the trigger is fired only when one of the specified columns is updated"
So insert a columns list for all columns except checked.
CREATE OR REPLACE TRIGGER "WORKPLACE"."UPD_PERSON"
BEFORE update of ID , Name , Created ON person
FOR each row
BEGIN
:new.last_updated := systimestamp;
END;
You can use a simple IF condition. "how can I changed this trigger so that when the 'checked' column is changed, that the last_updated column is NOT changed" means "update column last_updated only if 'checked' column is not changed"
CREATE OR REPLACE TRIGGER "WORKPLACE"."UPD_PERSON"
BEFORE update ON person
FOR each row
BEGIN
IF :old.checked = :new.checked THEN
:new.last_updated := systimestamp;
END IF;
END;
Note, in case checked can be NULL, you have to verify also on NULL values, e.g.
IF :old.checked = :new.checked or (:old.checked IS NULL AND :new.checked IS NULL) THEN
You can put condition also in header like this (note the missing colon : in condition)
CREATE OR REPLACE TRIGGER "WORKPLACE"."UPD_PERSON"
BEFORE update ON person
FOR each row
WHEN (old.checked = new.checked)
BEGIN
:new.last_updated := systimestamp;
END;
I have 2 tables 'label' and 'musician'
CREATE TABLE label
(labId varchar(10) NOT NULL PRIMARY KEY,
labName varchar(20) NOT NULL
);
CREATE TABLE musician
(musId varchar(10) NOT NULL PRIMARY KEY,
musName varchar(30) NOT NULL,
labId varchar(10) NOT NULL,
CONSTRAINT MusLabel FOREIGN KEY (labId) REFERENCES label(labId)
);
I created a trigger to limit the number of musicians a label can have within a
range of 1 to 5; so that for example a label x cannot have 6 musicians:
CREATE OR REPLACE TRIGGER before_musician_insert
BEFORE INSERT ON musician
FOR EACH ROW
DECLARE
total integer;
BEGIN
SELECT COUNT(*) INTO total
FROM musician, label
WHERE musician.labId=label.labId;
IF (total < 0 OR total > 5)
THEN
DBMS_OUTPUT.PUT_LINE('Invalid');
END IF;
END;
/
When I insert a 6th musician into the table with the same label ID, the insert statement does not 'trigger' the TRIGGER and the 6th value is added to the table.
I don't know how to fix this.
I tried a check constraint but with varchar values, it is not working either.
I appreciate your help.
Your code has multiple issues. For instance, it is not accessing :new. The trigger is on the wrong table. It has no error generation.
I might suggest something like this:
CREATE OR REPLACE TRIGGER before_labels_insert
BEFORE INSERT ON labels
FOR EACH ROW
DECLARE
v_total integer;
user_xcep EXCEPTION;
PRAGMA EXCEPTION_INIT( user_xcep, -20001 );
BEGIN
SELECT COUNT(*) INTO v_total
FROM labels l
WHERE l.labId = :new.labId;
IF (v_total >= 5) THEN
DBMS_OUTPUT.PUT_LINE('Invalid');
RAISE user_xcep
END IF;
END;
Your trigger fires BEFORE the insert, so the sixth entry doesn't exist when the query is executed.
If you want to error on the insert of the 6th entry, you can make it an AFTER trigger (and fire once per statement, rather than FOR EACH ROW).
Posted a question a couple of days ago and successfully got my trigger to work!
But having a few new problems.
I have two tables:
CREATE TABLE "ASSESSMENT"
( "ASSESSMENT_NAME" VARCHAR2(50) NOT NULL ENABLE,
"DEADLINE_DATE" DATE NOT NULL ENABLE,
CONSTRAINT "ASSESSMENT_PK" PRIMARY KEY ("ASSESSMENT_NAME") ENABLE
)
CREATE TABLE "ASSESSMENT_ANNOUNCEMENT"
( "ASSESSMENT_NAME" VARCHAR2(50) NOT NULL ENABLE,
"DEADLINE_DATE" DATE NOT NULL ENABLE,
"ATTENTION" VARCHAR2(500) NOT NULL ENABLE,
CONSTRAINT "ASSESSMENT_ANNOUNCEMENT_PK" PRIMARY KEY ("ASSESSMENT_NAME") ENABLE
)
The trigger I have:
CREATE OR REPLACE TRIGGER "TEST"
AFTER INSERT OR UPDATE OR DELETE
ON ASSESSMENT
FOR EACH ROW
BEGIN
IF :new.DEADLINE_DATE >= SYSDATE - 7
THEN
INSERT INTO ASSESSMENT_ANNOUNCEMENT(ASSESSMENT_NAME, DEADLINE_DATE ,ATTENTION)
VALUES(:new.ASSESSMENT_NAME, :new.DEADLINE_DATE, 'DEADLINE IS 7 DAYS OR LESS!');
END IF;
END;
Insert works correctly across the tables. But, when I update on the ASSESSMENT table, a new row is
inserted in the ASSESSMENT_ANNOUNCEMENT table - it is not updated.
A delete from the ASSESSMENT table removes the row from ASSESSMENT table but not the entry from
the ASSESSMENT_ANNOUNCEMENT table.
Any help and/or guidance would be fantastic!
If you want to update or delete a row in ASSESSMENT_ANNOUNCEMENT, you should do it explicitly using update or delete statement.
Use the following construction in your trigger:
IF INSERTING THEN
-- actions for inserting
ELSIF UPDATING THEN
-- actions for updating
ELSE
-- actions for deleting
END IF;
Just to give you a complete sample
CREATE OR REPLACE TRIGGER "TEST"
AFTER INSERT OR UPDATE OR DELETE
ON ASSESSMENT
FOR EACH ROW
BEGIN
IF INSERTING THEN
IF :new.DEADLINE_DATE >= SYSDATE - 7
THEN
INSERT INTO ASSESSMENT_ANNOUNCEMENT(ASSESSMENT_NAME, DEADLINE_DATE ,ATTENTION)
VALUES(:new.ASSESSMENT_NAME, :new.DEADLINE_DATE, 'DEADLINE IS 7 DAYS OR LESS!');
END IF;
ELSIF UPDATING THEN
UPDATE ASSESSMENT_ANNOUNCEMENT SET
ASSESSMENT_NAME=:new.ASSESSMENT_NAME,
DEADLINE_DATE=:new.DEADLINE_DATE,
ATTENTION='Deadline Updated'
WHERE ASSESSMENT_NAME=:old.ASSESSMENT_NAME;
ELSE
DELETE ASSESSMENT_ANNOUNCEMENT
WHERE ASSESSMENT_NAME=:old.ASSESSMENT_NAME;
END IF;
END;
Depending on your real business logic and size of PL/SQL code, it may be more clear to create three triggers
CREATE OR REPLACE TRIGGER "TEST_AI_TRG" AFTER INSERT ON ASSESSMENT ...
CREATE OR REPLACE TRIGGER "TEST_AU_TRG" AFTER UPDATE ON ASSESSMENT ...
CREATE OR REPLACE TRIGGER "TEST_AD_TRG" AFTER DELETE ON ASSESSMENT ...