Follows Clause in Triggers - Precedence of Triggers
CUST_ID NUMBER(4),
CUST_NAME VARCHAR2(20),
DOB DATE,
AGE NUMBER,
AGE_BUCKET VARCHAR2(20),
INSERTED_DT TIMESTAMP(0)
);
FOR EACH ROW
BEGIN
:NEW.age := ceil(months_between(sysdate,:new.dob)/12);
:NEW.Inserted_Dt := sysdate;
Dbms_output.put_line('Trigger TRG_BRI_ CUSTOMER_1 is fired');
End;
/
CREATE or REPLACE TRIGGER TRG_BRI_CUSTOMER_2
BEFORE
INSERT on CUSTOMER
FOR EACH ROW
DECLARE
v_age varchar2(20);
BEGIN
v_age := is_num(:NEW.Age);
IF v_age = 0 then
:NEW.Age_bucket :=
Case WHEN :NEW.Age > 65 then 'Senior Citizen'
WHEN :NEW.Age between 41 and 65 THEN 'Adult'
WHEN :NEW.Age between 18 and 40 THEN 'young Adult'
WHEN :NEW.Age between 13 and 18 THEN 'Teens'
ELSE 'Childhood' END;
ELSE
Dbms_output.put_line(' Age value is Not a number');
END IF;
Dbms_output.put_line('Trigger TRG_BRI_ CUSTOMER_2 is fired');
End;
Let us insert a record in the table.
Trigger TRG_BRI_ CUSTOMER_2 is fired
Trigger TRG_BRI_ CUSTOMER_1 is fired
1 row created.
CUST_ID CUST_NAME DOB AGE AGE_BUCKET INSERTED_DT
---------- ----------------- --------- ---------- -------------------- --------------------------
1 Raghu 01-MAY-99 18 12-DEC-16 04.58.10 PM
FOR EACH ROW
FOLLOWS TRG_BRI_CUSTOMER_1
DECLARE
v_age varchar2(20);
BEGIN
v_age := is_num(:NEW.Age);
IF v_age = 0 then
:NEW.Age_bucket :=
Case WHEN :NEW.Age > 65 then 'Senior Citizen'
WHEN :NEW.Age between 41 and 65 THEN 'Adult'
WHEN :NEW.Age between 18 and 40 THEN 'young Adult'
WHEN :NEW.Age between 13 and 18 THEN 'Teens'
ELSE 'Childhood' END;
ELSE
Dbms_output.put_line(' Age value is Not a number');
END IF;
Dbms_output.put_line('Trigger TRG_BRI_ CUSTOMER_2 is fired');
End;
Trigger TRG_BRI_ CUSTOMER _1 is fired
Trigger TRG_BRI_ CUSTOMER_2 is fired
1 row created.
SQL> select * from customer;
1 Raghu 01-MAY-99 18 12-DEC-16 05.34.07 PM
Because of the execution order, the second trigger is fired after the first one. Now we can see Both Age and AGE_BUCKET are populated.
Triggers are Named sub-programs, which are used to perform
some actions based on the triggering event, perform auditing and also to
implement business rules.
As we are aware that we can have multiple DML triggers on a
table. They can be of different types like row level and Statement level
triggers. We can have multiple triggers at different triggering timings and
triggering Events.
We can even have
multiple triggers in the same triggering event and triggering timing. That is,
we can have multiple BEFORE INSERT ROW LEVEL or AFTER INSERT ROW LEVEL or
BEFORE UPDATE INSERT FOR EACH ROW, etc.
Triggers which are in the same event and timing are fired
automatically when the corresponding triggering event happen on the associated
table. But, there is no guarantee of the order of execution of the triggers in
the versions till Oracle 10. Oracle has introduced FOLLOWS clause to control
the flow of execution of these triggers which are in the same type.
Here is a sample to implement FOLLOWS clause.
I have created a table CUSTOMER.
CREATE TABLE
CUSTOMER
(CUST_ID NUMBER(4),
CUST_NAME VARCHAR2(20),
DOB DATE,
AGE NUMBER,
AGE_BUCKET VARCHAR2(20),
INSERTED_DT TIMESTAMP(0)
);
I have created 2 triggers on this table in with same type,
triggering event and timing. Both of them are BEFORE INSERT and FOR EACH ROW
LEVEL.
They are –
1.
TRG_BRI_Customer_1 à Calculating the age based on
DOB before record is getting inserted.
CREATE or REPLACE
TRIGGER TRG_BRI_CUSTOMER_1
BEFORE
INSERT on CUSTOMERFOR EACH ROW
BEGIN
:NEW.age := ceil(months_between(sysdate,:new.dob)/12);
:NEW.Inserted_Dt := sysdate;
Dbms_output.put_line('Trigger TRG_BRI_ CUSTOMER_1 is fired');
End;
/
2.
TRG_BRI_Customer_2 :
-
Categorizes the customer based on the age which
is being calculated by TRG_BRI_Customer_1.
-
I have created a function IS_NUM to check
whether a value is a not null value or not. This trigger used this function to
check whether the calculated value is a valid value or no. If the value is a
not null value and is a number, it will assign respective age bucket to the
record. Else we see null.
CREATE or REPLACE TRIGGER TRG_BRI_CUSTOMER_2
FOR EACH ROW
DECLARE
v_age varchar2(20);
BEGIN
v_age := is_num(:NEW.Age);
IF v_age = 0 then
:NEW.Age_bucket :=
Case WHEN :NEW.Age > 65 then 'Senior Citizen'
WHEN :NEW.Age between 41 and 65 THEN 'Adult'
WHEN :NEW.Age between 18 and 40 THEN 'young Adult'
WHEN :NEW.Age between 13 and 18 THEN 'Teens'
ELSE 'Childhood' END;
ELSE
Dbms_output.put_line(' Age value is Not a number');
END IF;
Dbms_output.put_line('Trigger TRG_BRI_ CUSTOMER_2 is fired');
End;
Let us insert a record in the table.
SQL>
insert into customer (cust_id,cust_name,dob) values (1,'Raghu','01-may-99');
Age value is
Not a numberTrigger TRG_BRI_ CUSTOMER_2 is fired
Trigger TRG_BRI_ CUSTOMER_1 is fired
1 row created.
SQL>
select * from customer;
CUST_ID CUST_NAME DOB AGE AGE_BUCKET INSERTED_DT
---------- ----------------- --------- ---------- -------------------- --------------------------
1 Raghu 01-MAY-99 18 12-DEC-16 04.58.10 PM
You can make
out the AGE_BUCKET is null in the table. This is because By the time TRG_BRI_ CUSTOMER_2
is fired, TRG_BRI_ CUSTOMER_1 is still calculating Age of the customer.
The solution
here is to define the execution order in the second trigger to fire only after
the first one. We have to give FOLLOWS clause in the second trigger as follows
-
CREATE or REPLACE
TRIGGER TRG_BRI_CUSTOMER_2
BEFORE
INSERT on CUSTOMERFOR EACH ROW
FOLLOWS TRG_BRI_CUSTOMER_1
DECLARE
v_age varchar2(20);
BEGIN
v_age := is_num(:NEW.Age);
IF v_age = 0 then
:NEW.Age_bucket :=
Case WHEN :NEW.Age > 65 then 'Senior Citizen'
WHEN :NEW.Age between 41 and 65 THEN 'Adult'
WHEN :NEW.Age between 18 and 40 THEN 'young Adult'
WHEN :NEW.Age between 13 and 18 THEN 'Teens'
ELSE 'Childhood' END;
ELSE
Dbms_output.put_line(' Age value is Not a number');
END IF;
Dbms_output.put_line('Trigger TRG_BRI_ CUSTOMER_2 is fired');
End;
Here is the
output after inserting another record after adding follows clause in trigger.
SQL>
insert into customer (cust_id,cust_name,dob) values (2,'Raghuram','01-may-80');Trigger TRG_BRI_ CUSTOMER _1 is fired
Trigger TRG_BRI_ CUSTOMER_2 is fired
1 row created.
SQL> select * from customer;
CUST_ID
CUST_NAME DOB AGE AGE_BUCKET INSERTED_DT
---------- ----------------- --------- ---------- --------------------
-------------------------------1 Raghu 01-MAY-99 18 12-DEC-16 05.34.07 PM
2 Raghuram 01-MAY-80 37 young Adult 12-DEC-16 05.35.24 PM
Because of the execution order, the second trigger is fired after the first one. Now we can see Both Age and AGE_BUCKET are populated.
No comments:
Post a Comment