loop stuck on Trigger postgresql - sql

Im trying to create a trigger to controle parameters aren't NULL, but when i try to INSERT for example:
INSERT INTO puntuacions(puntuacio, contingut, data) VALUES (6,NULL,CURRENT_DATE);
Console start on a big LOOP trying to make INSERT inside function. Im not sure if i must do INSERT on function or at end of trigger.
BTW on avg select im trying to set an AVG value from a SELECT to insert on table.
I have this code:
FUNCTION:
create or replace function p_controla() returns trigger as $controla_puntuacions$
begin
IF new.puntuacio IS NULL OR new.contingut IS NULL OR new.data IS NULL
THEN
RAISE 'SIUSPLAU OMPLE TOTES LES DADES DE LA TAULA';
ELSE
INSERT INTO puntuacions(puntuacio, contingut, data) VALUES (new.puntuacio,new.contingut,new.data);
UPDATE continguts SET puntuacio = (SELECT AVG(puntuacio) FROM puntuacions WHERE contingut = new.contingut) WHERE idcontingut = new.contingut;
RAISE ' OK! ';
END IF;
END;
$controla_puntuacions$ language plpgsql;
TRIGGER:
create trigger controla_puntuacions
before insert on puntuacions
for each row execute procedure p_controla();

There are four problems with this trigger:
You expect that INSERT INTO puntuacions inserts a record which is handled by a trigger. A trigger does not work this way. INSERT INTO puntuacions in the trigger function instructs the database to insert another row. It will also fire this trigger again and will cause an infinite recursion. The row being inserted is in new. Values in new will be inserted to this table after the trigger returns new.
UPDATE continguts based on data in puntuacions is not appropriate in the before insert trigger, because the row is not inserted yet.
RAISE ' OK! ' raises an exception. So, the insert won't complete correctly even if all values are not null.
The trigger lacks return. When you fix 3, this will lead to a runtime error.
One issue is with the syntax for each row execute procedure. This syntax still works, but it is old-fashioned and now it is deprecated. The keyword FUNCTION should be used here instead of PROCEDURE.
For updating continguts you can create an after insert trigger.
If you want to insert a row after the trigger completes, it has to return new.
If you want just to display a message "OK", you can use RAISE NOTICE.
Potential solution:
The function for a before insert trigger:
create or replace function p_controla() returns trigger as $controla_puntuacions$
begin
IF new.puntuacio IS NULL OR new.contingut IS NULL OR new.data IS NULL
THEN
RAISE 'SIUSPLAU OMPLE TOTES LES DADES DE LA TAULA';
ELSE
RAISE NOTICE ' OK! ';
END IF;
RETURN new;
END;
$controla_puntuacions$ language plpgsql;
After insert trigger function:
create or replace function puntuacions_after_ins() returns trigger as $puntuacions_after_ins$
begin
UPDATE continguts SET puntuacio = (SELECT AVG(puntuacio) FROM puntuacions WHERE contingut = new.contingut) WHERE idcontingut = new.contingut;
RETURN new;
END;
$puntuacions_after_ins$ language plpgsql;
After insert trigger:
create trigger puntuacions_after_ins
after insert on puntuacions
for each row execute function puntuacions_after_ins();
The return value in the after insert function is ignored, but anyway this function has to return something.

Related

String modification trigger is not working

I am trying to write a trigger that executes after the INSERT completes on only newly inserted rows (I do not need to execute on old rows). The trigger should modify inserted string using split_part and replace functions.
The queries are as follows:
DROP TRIGGER IF EXISTS date_extraction ON t32upb
drop function if exists date_extraction();
CREATE FUNCTION date_extraction() RETURNS trigger AS $$
begin
NEW.filename := replace(split_part(old.filename,'_', 2), '.tif', '');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER
date_extraction
AFTER INSERT on
sentinel_2.t32upb
FOR EACH STATEMENT EXECUTE PROCEDURE
date_extraction();
What is wrong with the query? it is not working

PostgreSQL trigger not executing after update [duplicate]

Here is my trigger function
CREATE OR REPLACE FUNCTION test_table_insert()
RETURNS TRIGGER
AS $$
BEGIN
IF NEW.id IS NULL THEN
RAISE EXCEPTION 'id is null';
END IF;
UPDATE e_sub_agreement SET ro_id = NEW.id WHERE id = NEW.id;
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER test_table_insert AFTER INSERT ON e_sub_agreement FOR EACH ROW EXECUTE PROCEDURE test_table_insert();
The problem is that it doesn't update table e_sub_agreement. I checked NEW value and everything is good. It returns with the new id. If I change where statement id = "some existing id in table", then it works. It changes ro_id to the new id. How is it possible? My guess is that data has not been inserted into table and trigger function can't find row with the given id. But it's not how trigger's after insert function works. What's the magic?
An AFTER trigger can not change anything. Running an additional UPDATE is also quite inefficient. Change this to a BEFORE trigger and assign the value you want:
CREATE OR REPLACE FUNCTION test_table_insert()
RETURNS TRIGGER
AS $$
BEGIN
IF NEW.id IS NULL THEN
RAISE EXCEPTION 'id is null';
END IF;
NEW.ro_id := NEW.id;
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER test_table_insert
BEFORE INSERT ON e_sub_agreement
FOR EACH ROW EXECUTE PROCEDURE test_table_insert();
Note that the NOT NULL check is better done by defining the column as NOT NULL.

Postgresql delete record involving two tables and store this record in the third record

I'm trying to delete a record from the table 'student', where on a Cascade delete it will remove it from the 'entry' table. But before delete i need to store this record in the third table 'cancel'.
Here is what i worked out so far:
DELETE FROM "CMPS".student
WHERE sno = '1';
CREATE TRIGGER canceled BEFORE DELETE
ON entry
FOR EACH ROW
EXECUTE PROCEDURE trigger_backup_row
CREATE OR REPLACE FUNCTION trigger_backup_row(integer)
RETURNS trigger AS
$$
BEGIN
INSERT INTO cancel (eno, excode, sno) values (NEW.eno, NEW.excode, NEW.sno);
RETURN NEW;
END;
$$
language PLPGSQL
But comes back with an errors. Any help will be much appreciated.
I suppose you need:
CREATE OR REPLACE FUNCTION trigger_backup_row()
RETURNS trigger AS
$$
BEGIN
INSERT INTO cancel (eno, excode, sno) values (OLD.eno, OLD.excode, OLD.sno);
RETURN OLD;
END;
$$
language PLPGSQL
;
CREATE TRIGGER canceled BEFORE DELETE
ON entry
FOR EACH ROW
EXECUTE PROCEDURE trigger_backup_row()
;
trigger function do not use arguments
on delete yo udon't have any NEW row - just an OLD one

Postgresql trigger row not affected

I have try to make a trigger on a table call product. After inserting a product i get an error, that "NEW" variable is not affected yet.
Here is the trigger and user-defind function :
CREATE OR REPLACE FUNCTION updateProduitQteInitiale() RETURNS TRIGGER AS $example_table$
BEGIN
IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') THEN
UPDATE produit set qtestock= NEW.qteinitial where produit.pid = NEW.pid ;
return NEW ;
END IF;
RETURN NULL;
END;
$example_table$ LANGUAGE plpgsql;
And here is the trigger:
CREATE TRIGGER qteInitialTrigger AFTER INSERT OR UPDATE ON produit
FOR EACH ROW EXECUTE PROCEDURE updateProduitQteInitiale();
Is pid your primary id? Not sure what you want to do but I assume you want to set to the column qtestock value from column qteinitial (on the same row!). If I guessed it right then you can do this:
CREATE OR REPLACE FUNCTION updateProduitQteInitiale() RETURNS TRIGGER AS $example_table$
BEGIN
NEW.qtestock = NEW.qteinitial;
return NEW;
END;
$example_table$ LANGUAGE plpgsql;
CREATE TRIGGER qteInitialTrigger BEFORE INSERT OR UPDATE ON produit
FOR EACH ROW EXECUTE PROCEDURE updateProduitQteInitiale();

PL/PgSQL creating a conditional trigger on insert

I'm working on my first ever Trigger. When I'm doing an INSERT on table I want to conditionaly remove rows from other table.
Here is a trigger:
CREATE OR REPLACE FUNCTION clear_seen_by()
RETURNS trigger AS
$BODY$
BEGIN
IF (OLD.popup = '1') THEN
DELETE FROM news_seen_by;
END IF;
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Invoked by:
CREATE TRIGGER clear_seen_by
AFTER INSERT
ON news
FOR EACH STATEMENT
EXECUTE PROCEDURE clear_seen_by();
As an error I see that NEW or OLD (if I motify the trigger) is not declared/unknown. Where is the problem?
In an INSERT statement you do not have an OLD record defined.
You should use NEW.popup instead, and also declare the trigger to be FOR EACH ROW.
CREATE OR REPLACE FUNCTION clear_seen_by() RETURNS trigger AS
$BODY$
BEGIN
IF (NEW.popup = '1') THEN
DELETE FROM news_seen_by;
END IF;
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql VOLATILE COST 100;
CREATE TRIGGER
clear_seen_by
AFTER INSERT ON
news
FOR EACH ROW EXECUTE PROCEDURE
clear_seen_by();
You declare a trigger FOR EACH STATEMENT. Maybe you need FOR EACH ROW?
FOR EACH STATEMENT triggers do not have NEW and OLD.