I have a trigger function for a table test which has the following code snippet:
IF TG_OP='UPDATE' THEN
IF OLD.locked > 0 AND
( OLD.org_id <> NEW.org_id OR
OLD.document_code <> NEW.document_code OR
-- other columns ...
)
THEN
RAISE EXCEPTION 'Message';
-- more code
So I am statically checking all the column's new value with its previous value to ensure integrity. Now every time my business logic changes and I have to add new columns into that table, I will have to modify this trigger each time. I thought it would be better if somehow I could dynamically check all the columns of that table, without explicitly typing their name.
How can it be done?
In case of data cleanse activities there could be a necessity to loop over columns. Doing this dynamically will enable you to easily verify each column without writing to much ABAP code, as the code is valid for all columns. Since everybody knows how to loop over rows but not over columns I began my quest of finding the most proper solution.
Embed VBA to Loop through Each Cell in Every Row of a Table by Cell Reference Number If you want to loop through each cell in every row of a table in your Excel worksheet and get the cell reference number as the return value, then follow the steps discussed below.
Steps to loop through rows in a table until a blank cell with FOR Loop in VBA Excel are given below. At first, open Visual Basic Editor from the Developer tab and Insert a Module in the code window. After that, copy the following code and paste it into the code window.
Increment looping the column from the first row until the last row. MsgBox "Currently iterating cell " & Chr (Count + 64) & i Count = Count + 1 Loop i = i + 1 Loop
From 9.0 beta2 documentation about WHEN
clause in triggers, which might be able to be used in earlier versions within the trigger body:
OLD.* IS DISTINCT FROM NEW.*
or possibly (from 8.2 release notes)
IF row(new.*) IS DISTINCT FROM row(old.*)
Take a look at the information_schema, there is a view "columns". Execute a query to get all current columnnames from the table that fired the trigger:
SELECT
column_name
FROM
information_schema.columns
WHERE
table_schema = TG_TABLE_SCHEMA
AND
table_name = TG_TABLE_NAME;
Loop through the result and there you go!
More information can be found in the fine manual.
In Postgres 9.0 or later add a WHEN
clause to your trigger definition (CREATE TRIGGER
statement):
CREATE TRIGGER foo
BEFORE UPDATE
FOR EACH ROW
WHEN (OLD IS DISTINCT FROM NEW) -- parentheses required!
EXECUTE PROCEDURE ...;
Only possible for triggers BEFORE
/ AFTER
UPDATE
, where both OLD
and NEW
are defined. You'd get an exception trying to use this WHEN
clause with INSERT
or DELETE
triggers.
And radically simplify the trigger function accordingly:
...
IF OLD.locked > 0 THEN
RAISE EXCEPTION 'Message';
END IF;
...
No need to test IF TG_OP='UPDATE' ...
since this trigger only works for UPDATE
anyway.
Or move that condition in the WHEN clause, too:
CREATE TRIGGER foo
BEFORE UPDATE
FOR EACH ROW
WHEN (OLD.locked > 0
AND OLD IS DISTINCT FROM NEW)
EXECUTE PROCEDURE ...;
Leaving only an unconditional RAISE EXCEPTION
in your trigger function, which is only called when needed to begin with.
Read the fine print:
In a
BEFORE
trigger, theWHEN
condition is evaluated just before the function is or would be executed, so usingWHEN
is not materially different from testing the same condition at the beginning of the trigger function. Note in particular that theNEW
row seen by the condition is the current value, as possibly modified by earlier triggers. Also, aBEFORE
trigger'sWHEN
condition is not allowed to examine the system columns of theNEW
row (such asoid
), because those won't have been set yet.In an
AFTER
trigger, theWHEN
condition is evaluated just after the row update occurs, and it determines whether an event is queued to fire the trigger at the end of statement. So when anAFTER
trigger'sWHEN
condition does not return true, it is not necessary to queue an event nor to re-fetch the row at end of statement. This can result in significant speedups in statements that modify many rows, if the trigger only needs to be fired for a few of the rows.
Related:
Is it possible to dynamically loop through a table's columns?
Yes. Examples:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With