sql trigger - update/insert - postgresql

one thing I´m struggling with is the definition of triggers in SQL. I need to implement a code for a given table such that:
-for any new row inserted in the table, the trigger is activated and the table stores current date on the attribute date. the issue I have with the code included below is that updates all rows in the table, and onle want the inserted table to be updated with the current date.
CREATE FUNCTION func()
RETURNS trigger AS $$
DECLARE
value DATE;
BEGIN
SELECT CURRENT_DATE INTO fecha;
UPDATE tabla SET date = value;
RETURN NULL;
END;
$$LANGUAGE plpgsql;
CREATE TRIGGER date
AFTER INSERT ON table
FOR EACH ROW EXECUTE PROCEDURE func();
for any update on any row of the table, the trigger is activated and again, stores the current date on the attribute date.
CREATE FUNCTION func2()
RETURNS trigger AS $$
DECLARE
value DATE;
BEGIN
SELECT CURRENT_DATE INTO value;
SET NEW.date=value;
RETURN NULL;
END;
$$LANGUAGE plpgsql;
CREATE TRIGGER date
AFTER UPDATE ON table
FOR EACH ROW
EXECUTE PROCEDURE func2();

Use a BEFORE trigger instead that manipulates the row that is getting inserted/updated:
CREATE FUNCTION func()
RETURNS trigger AS $$
BEGIN
NEW.date = CURRENT_DATE ;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER date
BEFORE INSERT OR UPDATE ON table
FOR EACH ROW EXECUTE PROCEDURE func();

Related

Trigger function to update timestamp attribute when any value in the table is updated

I want to update the timestamp attribute 'register_updated' to the current_timestamp whenever any value is updated in the table.
This is my function
CREATE OR REPLACE FUNCTION fn_register_updated()
RETURNS trigger language plpgsql AS $$
BEGIN
UPDATE tb_register
SET register_updated = CURRENT_TIMESTAMP
WHERE (OLD.* IS DISTINCT FROM NEW.*);
RETURN NEW;
END;
$$;
CREATE TRIGGER tg_register_updated
BEFORE UPDATE
ON tb_register
FOR EACH ROW
EXECUTE PROCEDURE fn_register_updated();
But whenever I run an update on a table I receive the following error:
SQL statement "UPDATE tb_register
SET register_updated = CURRENT_TIMESTAMP"
PL/pgSQL function fn_register_updated() line 3 at SQL statement
SQL statement "UPDATE tb_register
SET register_updated = CURRENT_TIMESTAMP"
PL/pgSQL function fn_register_updated() line 3 at SQL statement
SQL statement "UPDATE tb_register
Any ideas on how to solve this?
I am struggling with the use of UPDATE within the body of the function.
Thank you,
Sample code for you:
CREATE OR REPLACE FUNCTION fn_register_updated()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
begin
new.register_updated = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$function$;
create trigger tg_register_updated before
update
on
tb_register for each row execute function fn_register_updated();

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();

Interpreting TG_TABLE_NAME as a value to update row in other table

I want to update a row in the master_table_info table with the latest timestamp whenever certain other tables are updated. Each row in the table corresponds to another table. I've created this function, but I cannot get TG_TABLE_NAME to be interpreted as a variable value and not a new column. I thus get the error column some_table does not exist. How do I interpret it as a value?
CREATE OR REPLACE FUNCTION master_table_timestamp()
RETURNS TRIGGER AS
$$
BEGIN
EXECUTE format('
UPDATE master_table_info
SET updated_at = NOW()
WHERE table_name = %I', TG_TABLE_NAME);
RETURN NULL;
END;
$$
language plpgsql;
CREATE TRIGGER master_table_timestamp
BEFORE UPDATE ON some_table
EXECUTE PROCEDURE master_table_timestamp();
EDIT
Based on the answer/comments so far and reading up the trigger documentation, I realized that I should use TG_TABLE_NAME and change to an AFTER trigger. However, modifying the table with the trigger produces no changes on master_table_info. What could be wrong?
CREATE OR REPLACE FUNCTION master_table_timestamp()
RETURNS TRIGGER AS
$$
BEGIN
UPDATE master_table_info
SET updated_at = NOW()
WHERE table_name = TG_TABLE_NAME;
RETURN new;
END;
$$
language plpgsql;
CREATE TRIGGER master_table_timestamp
AFTER UPDATE ON some_table
EXECUTE PROCEDURE master_table_timestamp();
2nd Edit
This code in my edit above (based on assistance from the answers) is correct. I just needed to force a manual refresh of the table for it to correctly show.
%I replaces the placeholder as an identifier. So the generated SQL would be
UPDATE master_table_info
SET updated_at = NOW()
WHERE table_name = some_table;
To replace a literal value you would need %L as a placeholder in the String. The %L placeholder takes care of properly quoting values, so if you use that, the generated string would be:
UPDATE master_table_info
SET updated_at = NOW()
WHERE table_name = 'some_table';
which is what you expected.
However there is no need for dynamic SQL to begin with. As you use that function in a before trigger it is important that you return a non-null value from it, otherwise the UPDATE statement would be cancelled.
CREATE OR REPLACE FUNCTION master_table_timestamp()
RETURNS TRIGGER AS
$$
BEGIN
UPDATE master_table_info
SET updated_at = NOW()
WHERE table_name = TG_TABLE_NAME;
RETURN new; --<< return a NON-NULL value here!
END;
$$
language plpgsql;

How to modify Trigger to update a single attribute in PostgreSQL

Here is my sample table.
CREATE TABLE employee_test(
idTst SERIAL PRIMARY KEY,
monthDownload VARCHAR(6),
changeDate DATE);
I am trying to create a function and trigger that would update changeDate attribute with a current date when monthDownload attribute is updated.
The function I have it works with one problem. It updates all records instead of the one that was updated.
CREATE OR REPLACE FUNCTION downloadMonthChange()
RETURNS TRIGGER AS
$$
BEGIN
IF NEW.monthDownload <> OLD.monthDownload THEN
UPDATE employee_test
SET changeDate = current_date
where OLD.idTst = NEW.idTst;
END IF;
RETURN NEW;
END;
$$
Language plpgsql;
Trigger
Create TRIGGER dataTest
AFTER UPDATE
ON employee_test
FOR EACH ROW
EXECUTE PROCEDURE downloadMonthChange();
When I execute the following Update statement:
UPDATE employee_test SET monthDownload = 'oct12'
WHERE idTst = 1;
All changeDate rows get update with a current date.
Is there a way to have only a row with changed record to have a current date updated.
If you use a before trigger you can write directly to NEW
CREATE OR REPLACE FUNCTION downloadMonthChange()
RETURNS TRIGGER AS
$$
BEGIN
IF NEW.monthDownload <> OLD.monthDownload THEN
NEW.changeDate = current_date;
END IF;
RETURN NEW;
END;
$$
Language plpgsql;
the other option when you must use an after trigger is to include the primary key in the where clause. It appears that you were trying to do this, but you had a spurious OLD in the query. beause of that the where clause was only looking at the record responsible for the trigger call, and not limiting which records were to be updated.
IF NEW.monthDownload <> OLD.monthDownload THEN
UPDATE employee_test
SET changeDate = current_date
where idTst = NEW.idTst;

Postgres trigger function

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();