I have a trigger that looks like:
create trigger syncdataprodTrigger
after insert or update or delete on schema.table
for each row
execute procedure schema.schemaProdTableDataSync();
and a function that contains this snippet:
elseif (TG_OP = 'DELETE') then
delete from schema.table where id1 = old.id1;
RETURN NEW;
What I am expecting is that when a row is deleted from the first table it deletes it from the second table, but I am not getting this. What am I doing wrong and what can I be doing differently?
Got this to work, turns out that derps happen and the trigger needed to be changed to the right table...
Related
I have created a view which has columns that i need to track for any change and load it into a history table. I created a Trigger as below and when i execute change, it only updates the History but does not add a new updated record. Any idea what im doing wrong?
create or replace function asset_h_fn() returns trigger
LANGUAGE plpgsql
as $$
begin
if (asset = 'Insert') then
insert into asset_history (sys_period,col1,col2,col3,col4,col5,col6)
values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.col1, OLD.col2, OLD.col3, OLD.col4, OLD.col5);
NEW.sys_period = tstzrange(current_timestamp,null);
return new;
return old;
end if;
end $$ ;
The RETURN OLD; in your code is fortunately unreachable; remove it.
You don't show us the CREATE TRIGGER statement, but it must be an INSTEAD OF trigger.
A view does not hold any data, it is an SQL statement with a name. So if you want a new row to appear in the view, you have to add a second INSERT to the trigger function that inserts a row into the table(s) on which the view is defined.
Well, It depends on how do you define your trigger...
Looking at your code I suppose you should use CREATE TRIGGER <trigger_name> BEFORE INSERT OR UPDATE ON <table_name> FOR EACH ROW EXECUTE PROCEDURE asset_h_fn();
The key here is BEFORE INSERT - if you wish to alter somehow inserted into original table data... If you don't wish to alter it, you should probably use AFTER INSERT.
You may read more about defining triggers and see some examples in official docs
I have a table called car and another table called inventory.
car has a column called needs_oil_change (bool)
inventory has a column called oil_change_due_count INTEGER
I want to create a trigger that will incremented or decrement the inventory.oil_change_due_count whenever a car.oil_change_due_count is changed (or whenever a new car record is inserted, or deleted).
So, in short, I want a trigger to keep the inventory summary count column oil_change_due_count synchronized as car records are created/deleted/updated.
I've tried to follow some docs online like these:
https://w3resource.com/PostgreSQL/postgresql-triggers.php
https://dataegret.com/2017/10/postgresqls-transition-relations/
and others.
I haven't been able to create one that works yet.
How would I write a trigger that could handle that logic?
I just found this:
PostgreSQL: Checking for NEW and OLD in a function for a trigger
not sure if it will answer my question, but I will try to learn from that and see if I can apply to my question.
First of all you need to create a trigger function to handle the logic, in postgresql you can do something like this
CREATE OR REPLACE FUNCTION fn_oil_change() RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'DELETE') THEN
UPDATE inventory SET oil_change_due_count = oil_change_due_count - OLD.oil_change_due_count;
RETURN OLD;
ELSIF (TG_OP = 'UPDATE') THEN
... some logic to hangle update
RETURN NEW
ELSIF (TG_OP = 'INSERT') THEN
... some logic to hangle update
RETURN NEW;
END IF;
RETURN NULL; -- result is ignored since this is an AFTER trigger
END;
$$ LANGUAGE plpgsql;
and then create the trigger itself
CREATE TRIGGER tg_oil_change
AFTER INSERT OR UPDATE OR DELETE ON car
FOR EACH ROW EXECUTE PROCEDURE fn_oil_change();
Something more or less like this, right now I can't test the code, and you'll need to think how to handle the update.
I'm trying to create a function + trigger that will update my "modif" attribut to current date when there is an update or insert on my table called "nada".
the code work well but all the rows are affected.I only want the current date on the rows that were updated.
Any idea ?
This is my code so far:
CREATE OR REPLACE FUNCTION public.maj_modif()
RETURNS "trigger" AS
$BODY$
BEGIN
NEW.modif:= (SELECT current_date);
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS maj_modif ON public.nada;
CREATE TRIGGER maj_modif BEFORE INSERT OR UPDATE ON public.nada
FOR EACH ROW
EXECUTE PROCEDURE public.maj_modif();
If I try the same code without "FOR EACH ROW" in the trigger I get this erreur: « new » is not affected yet (...) The structure of the registration line is not yet determined.
I assume that you only want the trigger to fire if any columns were actually changed.
That can be done with
CREATE TRIGGER maj_modif BEFORE UPDATE ON public.nada
FOR EACH ROW
WHEN OLD <> NEW
EXECUTE PROCEDURE public.maj_modif();
That only works for UPDATE, because on INSERT OLD is not defined. Define the INSERT trigger without the WHEN clause.
I'm trying to create a trigger in DB2 (AS400) to insert/delete a row into a table when an insert/delete is triggered on a different table, but I need to use information about the triger table.
The example would be I would like is like this (column 1 from table 1 and table 2 are the same and unique in table 2):
CREATE TRIGGER MY_TRIGGER
AFTER INSERT OR DELETE ON DB1.TABLE1
BEGIN
IF INSERTING
THEN INSERT INTO DB1.TABLE2 (Col1, Col2) VALUES (Db1.TABLE1.Col1, 0);
ELSEIF DELETING
THEN DELETE FROM Db1.TABLE2 WHERE Col1=TABLE1.Col1;
END IF;
END
But this doesn't work (it doesn't recognize TABLE1.Col1 on insert/delete statements).
Also it would prompt me an error (I guess) since it would create a duplicate key when a second row is inserted in Table 1. How could I avoid errors (just skip the insert) when the Table2.Col1 already exists?
Try adding correlation names like this:
CREATE TRIGGER MY_TRIGGER
AFTER INSERT OR DELETE ON DB1.TABLE1
REFERENCING OLD ROW AS OLD
NEW ROW AS NEW
BEGIN
IF INSERTING
THEN INSERT INTO DB1.TABLE2 (Col1, Col2) VALUES (NEW.Col1, 0);
ELSEIF DELETING
THEN DELETE FROM Db1.TABLE2 WHERE Col1=OLD.Col1;
END IF;
END
The trigger has access to both the old and new image of a row. You need to tell it which to use. BTW, only the update action populates both the old and new image. Insert only provides the new image, and delete only provides the old image. One might think that SQL could figure that out, but no, you still have to tell it explicitly.
EDIT This is the final trigger actually used (from comments, thank you #MarçalTorroella)
CREATE TRIGGER MY_TRIGGER
AFTER INSERT OR DELETE ON DB1.TABLE1
REFERENCING OLD ROW AS OLD
NEW ROW AS NEW
FOR EACH ROW MODE DB2ROW
BEGIN
DECLARE rowcnt INTEGER;
IF INSERTING THEN
SELECT COUNT(*)
INTO rowcnt
FROM DB1.TABL2
WHERE Col1 = NEW.Col1;
IF rowcnt = 0 THEN
INSERT INTO DB1.TABLE2 (Col1, Col2)
VALUES (NEW.Col1, 0);
END IF;
ELSEIF DELETING THEN
DELETE FROM Db1.TABLE2
WHERE Col1=OLD.Col1;
END IF;
END
I've created the following table:
CREATE TABLE updates
(
"table" text,
last_update timestamp without time zone
)
I want to update it whenever any table is updated, the problem is I don't know how, could someone please help me turn this pseudocode into a trigger?
this = current table on whitch operation is performed
ON ALTER,INSERT,DELETE {
IF (SELECT COUNT(*) FROM updates where table = this) = 1
THEN
UPDATE updates SET last_update = timeofday()::timestamp WHERE `table`=this
ELSE
INSERT INTO updates VALUES (this,timeofday()::timestamp);
}
You need a trigger function that is called whenever one of your tables is "updated", assuming that you mean that an INSERT, UPDATE, or DELETE is successfully executed. That trigger function would look like this:
CREATE FUNCTION log_update() RETURNS trigger AS $$
BEGIN
UPDATE updates SET last_update = now() WHERE "table" = TG_TABLE_NAME;
IF NOT FOUND THEN
INSERT INTO updates VALUES (TG_TABLE_NAME, now());
END IF;
IF (TG_OP = 'DELETE') THEN
RETURN OLD;
ELSE
RETURN NEW;
END IF;
END; $$ LANGUAGE PLPGSQL;
Every table that has to be logged this way needs to have a trigger associated with it like this:
CREATE TRIGGER ZZZ_mytable_log_updates
AFTER INSERT OR UPDATE OR DELETE ON mytable
FOR EACH ROW EXECUTE PROCEDURE log_update();
A few comments:
Trigger functions are created with PL/PgSQL; see chapter 40 in the documentation. Trigger functions come with some automatic parameters such as TG_TABLE_NAME.
Don't use reserved words ("table" in your case) as column names. Actually, in this case you are better off using the oid of the table, with the associated TG_RELID automatic parameter. It takes up less storage, it is faster, and it avoids confusion between tables with the same name in different schemas of your database. You can use the pg_tables system catalog table to look up the table name from the oid.
You must return the proper value depending on the operation, or the operation may fail. INSERT and UPDATE operations need to have NEW returned; DELETE needs to have OLD returned.
The name of the trigger starts with "ZZZ" to make sure that it fires after any other triggers on the same table have succeeded (they are fired in alphabetical order). If a prior trigger fails, this trigger function will not be called, which is the proper behaviour because the insert, update or delete will not take place either.