Postgres trigger function - postgresql

I need help in Postgres triggers.
I have table with 2 columns:
sold boolean;
id_shop int;
It stores if item is sold, or at which shop its located at.
I need a trigger, if I change the "sold" to true, then it also changes the id_shop to NULL (It can't be in shop if sold...)
I tried different ways, but it doesn't work or gives an error on update cmd...
create or replace function pardota_masina_veikals() RETURNS trigger AS $pardota_masina$
begin
IF NEW.sold=true THEN
update masinas
SET id_shop=null WHERE id=NEW.id;
END IF;
RETURN NEW;
END;
$pardota_masina$ LANGUAGE plpgsql;
CREATE TRIGGER pardota_masina_nevar_but_veikala
AFTER INSERT OR UPDATE ON masinas FOR EACH ROW EXECUTE PROCEDURE pardota_masina_veikals();

First of all you need a before trigger if you want to change a value of the row being updated (or inserted)
Secondly you don't need to "update" the table, just assign the new value to the NEW row:
create or replace function pardota_masina_veikals()
RETURNS trigger
AS
$pardota_masina$
begin
IF NEW.sold=true THEN
NEW.id_shop = NULL;
END IF;
RETURN NEW;
END;
$pardota_masina$
LANGUAGE plpgsql;
CREATE TRIGGER pardota_masina_nevar_but_veikala
BEFORE INSERT OR UPDATE ON masinas
FOR EACH ROW EXECUTE PROCEDURE pardota_masina_veikals();

Related

How can I set the date when some row is created? I'm trying to use only Triggers and Functions at PostgreSQL

I have a table called recipes and my goal is for each time that I insert a new row, the column created_at, of this new row, automatically receives the value NOW().
I manage to do something like this on the column updated_at creating this function and trigger, and it's working fine.
CREATE OR REPLACE FUNCTION public.trigger_set_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER set_timestamp
BEFORE UPDATE ON recipes
FOR EACH ROW
EXECUTE PROCEDURE trigger_set_timestamp();
But after I changed the code to set the created_at nothing happens and the Postgres doesn't point any errors.
CREATE OR REPLACE FUNCTION public.trigger_set_timestamp_created_at()
RETURNS trigger AS $$
BEGIN
NEW.created_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER set_timestamp_created_at
AFTER INSERT ON recipes
FOR EACH ROW
EXECUTE PROCEDURE trigger_set_timestamp_created_at();

postgresql - trigger function with condition

I'm trying to create a trigger with a condition. Based on the geom length I want the attribute "nom" (= name) to be written in upper case or lower case.
here's what I have:
CREATE OR REPLACE FUNCTION public.test_upper_lower()
RETURNS trigger AS
$BODY$
BEGIN
NEW.dummy:= (ST_Length(new.geom));
if (SELECT dummy FROM ligne_ligne)>100
then NEW.nom:= LOWER(nom) FROM ligne_ligne;
else NEW.nom:= UPPER(nom) FROM ligne_ligne;
end if;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
DROP trigger IF EXISTS test_upper_lower on public.ligne_ligne;
CREATE trigger test_upper_lower BEFORE INSERT OR UPDATE on public.ligne_ligne
FOR EACH ROW
EXECUTE PROCEDURE public.test_upper_lower();
With this I have a "more than one row returned by a subquery" error
Based on other questions on this forum I tried it using case instead of if and using when in the trigger itself not the function but neither are working
Any ideas ?
Thanks
You don't need (or can actually) use SELECT statements to access data from the inserted row.
The part SELECT dummy FROM ligne_ligne returns all rows from that table - not just from the one relevant to the trigger.
As you just want to check the value you just calculated, simply use new.dummy at that point:
CREATE OR REPLACE FUNCTION public.test_upper_lower()
RETURNS trigger AS
$BODY$
BEGIN
NEW.dummy:= ST_Length(new.geom);
if new.dummy > 100 then --<< no SELECT necessary
NEW.nom:= LOWER(new.nom); --<< no "FROM", just access the value
else
NEW.nom:= UPPER(new.nom);
end if;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;

PSQL Add value from row to another value in the same row using triggers

I have a test table with three columns (file, qty, qty_total). I will input multiple rows like this for example, insert into test_table (file,qty) VALUS (A,5);. What i want is for on commit is for a trigger to take the value from qty and add it to qty_total. As what will happen is that this value will get updated as this example demonstrates. Update test_table set qty = 10 where file = A; So the qty_total is now 15. Thanks
Managed to solve this myself. I created a trigger function `CREATE FUNCTION public.qty_total()
RETURNS trigger
LANGUAGE 'plpgsql'
COST 100.0
VOLATILE NOT LEAKPROOF
AS $BODY$
BEGIN
IF TG_OP = 'UPDATE' THEN
NEW."total" := (OLD.total + NEW.col2);
RETURN NEW;
ELSE
NEW."total" := NEW.col2;
RETURN NEW;
END IF;
END;
$BODY$;
ALTER FUNCTION public.qty_total()
OWNER TO postgres; This was called by a trigger CREATE TRIGGER qty_trigger
BEFORE INSERT OR UPDATE
ON public.test
FOR EACH ROW
EXECUTE PROCEDURE qty_total(); now when i insert a new code and value, the value is copied to the total, when it is updated, the value is added to the total and i have my new qty_total. This may not have the best error catching in it, but since i am passing the data from php, i am happy to make sure the errors are caught and removed.

Postgres - ´after update´ trigger doesn't fire

I have this table for which one of the columns is to be filled with values from other columns of the same table (these other columns represent a taxonomic hierarchy whose lowest level I wish to store in this other column).
To achieve this I implemented the following trigger:
CREATE OR REPLACE FUNCTION get_taxon()
RETURNS TRIGGER LANGUAGE plpgsql AS
$BODY$
BEGIN
UPDATE taxon SET taxon = coalesce(subespecie, especie, genero, subfamilia, familia, infraordem, subordem, ordem, superordem, subclasse, classe, subphylum, phylum, reino )
WHERE taxon IS NULL;
RETURN NEW;
END
$BODY$
VOLATILE;
CREATE TRIGGER update_taxon
AFTER INSERT OR UPDATE ON taxon
FOR EACH STATEMENT
WHEN (pg_trigger_depth() = 0) -- Prevent recursive trigger calls
EXECUTE PROCEDURE get_taxon();
When I insert a new record the trigger works as expected, but if I update an existing record, nothing happens - the trigger just ignores UPDATE operations and I don't know why.
Can anyone shed some light on this please?
After your statement trigger first fired all records in the table should have their taxon field updated with the best available information. When you update a record you may want to update the taxon value, but you are better off with a BEFORE INSERT OR UPDATE FOR EACH ROW trigger. The only new data is contained in the row for which the trigger fires, of course. So try this:
CREATE OR REPLACE FUNCTION get_taxon()
RETURNS TRIGGER LANGUAGE plpgsql AS
$BODY$
BEGIN
NEW.taxon := coalesce(NEW.subespecie, NEW.especie, NEW.genero, NEW.subfamilia,
NEW.familia, NEW.infraordem, NEW.subordem, NEW.ordem, NEW.superordem,
NEW.subclasse, NEW.classe, NEW.subphylum, NEW.phylum, NEW.reino);
RETURN NEW;
END;
$BODY$ VOLATILE;
CREATE TRIGGER update_taxon
BEFORE INSERT OR UPDATE ON taxon
FOR EACH ROW EXECUTE PROCEDURE get_taxon();

How to apply a update after an inser or update POSTGRESQL Trigger

How to apply an update after an insert or update in POSTGRESQL; I have got a table which has a field lastupdate; I want that field to be set up whenever the row is updated or when it was inserted.
I tried this trigger, but It is not working! HELP!!
CREATE OR REPLACE FUNCTION fn_update_profile()
RETURNS TRIGGER AS $update_profile$
BEGIN
IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE' ) THEN
UPDATE profile SET lastupdate=now() where oid=OLD.oid;
RETURN NULL;
ELSEIF (TG_OP = 'DELETE') THEN
RETURN NULL;
END IF;
RETURN NULL; -- result is ignored since this is an AFTER trigger
END;
$update_profile$ LANGUAGE plpgsql;
Your trigger function can be a lot easier than you had. Keep in mind that PG will do the update or the insert on the original table, you only have to deal with keeping the profile table up-to-date:
CREATE OR REPLACE FUNCTION fn_update_profile()
RETURNS TRIGGER AS $update_profile$
BEGIN
UPDATE profile SET lastupdate = now() WHERE oid = NEW.oid;
RETURN NEW;
END;
$update_profile$ LANGUAGE plpgsql;
The INSERT and UPDATE trigger functions both use the NEW parameter; the INSERT trigger function does not have the OLD parameter. You should always return NEW from the trigger function if successful (or OLD from a DELETE trigger), even if it is an AFTER INSERT OR UPDATE trigger; the whole operation will be rolled back if NULL is returned. If you then define the actual trigger to fire after the insert or update, you should be good:
CREATE TRIGGER tr_update_profile
AFTER INSERT OR UPDATE ON my_table
FOR EACH ROW EXECUTE PROCEDURE fn_update_profile();