Last week I had a requirement to create a trigger on a table that had to perform some logic and then run additional updates based on the outcome of the logic. The logic ran into multiple IF statements resulting in long messy code. Additionally, there was second requirement to execute this chunk of code from two places within the trigger functionality. I moved the code to a subprogram within the trigger’s PL/SQL logic resulting in a modular structure. This is a simplified example of the trigger code to demonstrate the technique.
The below lines declare a subprogram with some logic that creates an update statement. The EXECUTE IMMEDIATE is commented out for testing and demonstration:
PROCEDURE perform_calculations(cust_num number) IS BEGIN v_upd_sql :=''; IF :OLD.CUST_ZIP <> :NEW.CUST_ZIP THEN v_upd_sql := ' UPDATE DEAN_CUSTOMER SET CUST_ZIP_OLD = ' || :OLD.CUST_ZIP || ' WHERE CUST_NUM = ''' || CUST_NUM || ''''; END IF; --EXECUTE IMMEDIATE v_upd_sql; dbms_output.put_line('SQL --->' || v_upd_sql); END;
The below line of code calls the subprogram:
perform_calculations(:old.cust_num);
In the real-world scenario, I was working on, the code issued a BULK COLLECT similar to below and ran the subprogram for each row collected:
v_main_sql := ' SELECT ROWID FROM ' || v_table_name || ' WHERE COL01 = ' :OLD.COL01; EXECUTE IMMEDIATE v_main_sql BULK COLLECT INTO var01; FOR i IN 1..var01.COUNT LOOP perform_calculations(var01(i)); END LOOP;
“var01” was defined as shown below:
TYPE var01_type IS TABLE OF ROWID; Var01 var01_type;
Code
create or replace TRIGGER UPDATE_TRIGGER AFTER UPDATE ON DEAN_CUSTOMER FOR EACH ROW DECLARE v_upd_sql VARCHAR2(8000); table_not_found EXCEPTION; PRAGMA EXCEPTION_INIT (table_not_found, -942); PROCEDURE perform_calculations(cust_num number) IS BEGIN v_upd_sql :=''; IF :OLD.CUST_ZIP <> :NEW.CUST_ZIP THEN v_upd_sql := ' UPDATE DEAN_CUSTOMER SET CUST_ZIP_OLD = ' || :OLD.CUST_ZIP || ' WHERE CUST_NUM = ''' || CUST_NUM || ''''; END IF; --EXECUTE IMMEDIATE v_upd_sql; dbms_output.put_line('SQL --->' || v_upd_sql); END; BEGIN dbms_output.put_line(' '); dbms_output.put_line('********** Trigger DC invoked **********'); dbms_output.put_line(' '); perform_calculations(:old.cust_num); END;
Table definition
CREATE TABLE DEAN_CUSTOMER ( “CUST_NUM" NUMBER(8,0), "CUST_NAME" VARCHAR2(10 BYTE), "CUST_ZIP" NUMBER(12,0), "CUST_ZIP_OLD" NUMBER(12,0) ) SEGMENT CREATION DEFERRED PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING TABLESPACE "USERS" ;