Move Data from One table to other table by using trigger in postgreSQL - sql

I have the requirement to move data from one table to another table when the value of one of the columns is updated. And I just want to move the updated row to the new table.
Below is my trigger that I have written. The issue with my code is, that it is moving all the data and not just the row which was updated. Can anyone give a suggestion?
create or replace function moveToAC1ControlHist()
returns trigger as $$
begin if NEW.file_status='CO'
then
insert into ac1_control_hist (file_status,identitifier)
(
select file_status,identitifier
from
ac1_control where new.FILE_STATUS = 'CO'
);
end if;
return new;
end;
$$ language plpgsql;
create TRIGGER AC1_CONTROL_TRIGGER AFTER update of file_status ON AC1_CONTROL
FOR EACH ROW when (new.file_status ='CO')EXECUTE PROCEDURE moveToAC1ControlHist();

I think the logic you want is:
create or replace function moveToAC1ControlHist()
returns trigger as
$$
begin
insert into ac1_control_hist (file_status,identitifier)
values (new.file_status, new.identitifier);
return null;
end;
$$ language plpgsql;
create trigger ac1_control_trigger
after update of file_status on ac1_control
for each row
when (new.file_status ='co')
execute function movetoac1controlhist()
;
Rationale:
you just want to copy (part of) the row being updated, so there is no need to select; you can access the values of the current row with new in a row-level trigger
the trigger definition filters on new file_status that is equal to 'CO', so there is no need for a if construct in the function
this is an after trigger, so you can just return null - the result is discarded anyway

Related

PostgeSQL trigger before insert unique value

Is there any variant to create a trigger before insert and if the value is a value that exists already in table, just update it. I know about 'ON DUBLICATE KEY' or a 'ON CONFLICT' in PostgreSQL but I need a trigger just because it's a task in my university.
I tried to create it, but I get just an error about duplicate keys.
CREATE or replace FUNCTION trigger_function()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS $$
BEGIN
IF new.name in (select name from "Test")
then
update "Test" set intt = new.intt where name = new.name;
end if ;
return new;
END;
$$
CREATE TRIGGER trigger_name
BEFORE insert
ON "Test"
for each row
EXECUTE PROCEDURE trigger_function();
Is it possible to create such trigger?
Read the docs plpgsql trigger function:
Row-level triggers fired BEFORE can return null to signal the trigger manager to skip the rest of the operation for this row (i.e., subsequent triggers are not fired, and the INSERT/UPDATE/DELETE does not occur for this row).
So RETURN NULL after the UPDATE statement inside the if andRETURN NEW when the if is false. Then the INSERT will happen if the name is unique.

Insert records from a View into a Table via a Trigger

I would like to insert values from a view into a table, via a trigger set against the view.
I'm trying to add records to the table where the view has "newer" updated records. I need to use the view because of the way the data is transformed. To trigger I would want to create an IF for when table.column1 <> view.column1 and table.column2 <> view.column2 for example. This would then add that "newer" record
What is the best way to achieve this ?
I am using PostgreSQL. I tried this but it won't work because it's a view
CREATE or REPLACE FUNCTION function_name
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
IF (NEW.VIEW_Colummn1 = OLD.Table_column1 AND NEW.VIEW_Colummn2 = OLD.Table_column2 AND NEW.VIEW_Column3 <> OLD.Table_column3)
OR
(NEW.VIEW_Colummn1 = OLD.Table_column1 AND NEW.VIEW_Colummn2 = OLD.Table_column2)
THEN INSERT INTO "Table"(Column1,Column2,Column3,Column4,Column5)
VALUES(NEW.VIEW_Colummn1,NEW.VIEW_Colummn2,NEW.VIEW_Colummn3,NEW.VIEW_Colummn4, NEW.VIEW_Colummn5);
END IF;
RETURN NEW;
END;
$$
CREATE TRIGGER trigger_name
After UPDATE
ON VIEW
FOR EACH ROW
EXECUTE PROCEDURE function_name();

Trigger postgreSQL

So. I tried made a trigger for updating quality medicament( i take quality from delivery.quality and put in medicaments.quality)
create or replace function addedmed()
returns trigger
language plpgsql
as
$$
begin
update medicaments set medicaments.quality = delivery.quality + medicaments.quality
where medicaments.id_med = delivery.id_med_del;
end;
$$;
and then - i try insert data to delivery
insert into delivery(id_del,id_provider,date_of_get,id_worker_del,id_med_del,quality)
values (default, 3 , current_timestamp ,1 ,6 ,10);
and then i have a exception -
ЗАПРОС: update medicaments set medicaments.quality = delivery.quality + medicaments.quality
where medicaments.id_med = delivery.id_med_del
КОНТЕКСТ: PL/pgSQL function addedmed() line 3 at SQL statement
so, pls help me, because i dont know how resolve it
This is not valid trigger function code. If you want to refer to the row being inserted in delivery, then use pseudo-table new, not delivery.
create or replace function addedmed()
returns trigger
language plpgsql
as $$
begin
update medicaments set quality = quality + new.quality where id_med = new.id_med_del;
return new;
end;
$$;
Note that the trigger returns the new record. You can then actually create the trigger as follows:
create trigger trg_addedmed
before insert on delivery
for each row
execute addedmed()
;
I defined a before insert trigger, you can change that to after insert if you prefer (in that case you can return null instead of new).

PostgreSQL Update trigger

I have a table:
CREATE TABLE annotations
(
gid serial NOT NULL,
annotation character varying(250),
the_geom geometry,
"rotationAngle" character varying(3) DEFAULT 0,
CONSTRAINT annotations_pkey PRIMARY KEY (gid),
CONSTRAINT enforce_dims_the_geom CHECK (st_ndims(the_geom) = 2),
CONSTRAINT enforce_srid_the_geom CHECK (st_srid(the_geom) = 4326)
)
And trigger:
CREATE TRIGGER set_angle
AFTER INSERT OR UPDATE
ON annotations
FOR EACH ROW
EXECUTE PROCEDURE setangle();
And function:
CREATE OR REPLACE FUNCTION setAngle() RETURNS TRIGGER AS $$
BEGIN
IF TG_OP = 'INSERT' THEN
UPDATE annotations SET "rotationAngle" = degrees( ST_Azimuth( ST_StartPoint(NEW.the_geom), ST_EndPoint(NEW.the_geom) ) )-90 WHERE gid = NEW.gid;
RETURN NEW;
ELSIF TG_OP = 'UPDATE' THEN
UPDATE annotations SET "rotationAngle" = degrees( ST_Azimuth( ST_StartPoint(NEW.the_geom), ST_EndPoint(NEW.the_geom) ) )-90 WHERE gid = NEW.gid;
RETURN NEW;
END IF;
END;
$$ LANGUAGE plpgsql;
And when new row inserted in table or row edited i want to field rotationAngle setted with function result.
But when i inserting a new row in table function not work. I mean thath rotationAngle value not changed.
What can be wrong?
You are triggering an endless loop. Simplify the trigger function:
CREATE OR REPLACE FUNCTION set_angle()
RETURNS trigger
LANGUAGE plpgsql AS
$func$
BEGIN
NEW."rotationAngle" := degrees(
ST_Azimuth(
ST_StartPoint(NEW.the_geom)
, ST_EndPoint(NEW.the_geom)
)
) - 90;
RETURN NEW;
END
$func$;
Assign to NEW directly. No WHERE in this case.
You must double-quote illegal column names. Better not to use such names to begin with.
Recent related answer.
Code for insert & upgrade is the same. I folded into one code path.
Use a BEFORE trigger. This way you can edit columns of the triggering row directly before they are saved:
CREATE TRIGGER set_angle
BEFORE INSERT OR UPDATE ON annotations
FOR EACH ROW EXECUTE PROCEDURE set_angle();
However
If you are just trying to persist a functionally dependent value in the table (and there are no other considerations): Don't. Use a view or a generated column instead:
Store common query as column?
Then you don't need any of this.
There are multiple things wrong here.
1) When you insert a row 'A' the function setAngle() is called. But in the function you are calling another update within the function which will trigger the function again, and again, and so on...To fix this don't issue a update! Just update the NEW records value independently and return it.

INSTEAD OF DELETE trigger (Postgresql)

I would like to disable the DELETE statement on a table.
What I need to do is a SET a field value instead of removing the respective record.
So far I have tried the following:
CREATE TRIGGER delete_trg
INSTEAD OF DELETE
ON schema.tbl
FOR EACH ROW
EXECUTE PROCEDURE schema.tbl_delete_fn();
My schema.tbl_delete_fn() function is as follows:
CREATE OR REPLACE FUNCTION schema.tbl_delete_fn()
RETURNS trigger AS
BEGIN
NEW.deleted := true;
RETURN NEW;
END;
So far this doesn't seem to work... any ideas?
You want a BEFORE DELETE trigger whose function returns NULL and the row variable is OLD, not NEW.
CREATE TRIGGER delete_trg
BEFORE DELETE
ON schema.tbl
FOR EACH ROW
EXECUTE PROCEDURE schema.tbl_delete_fn();
CREATE OR REPLACE FUNCTION schema.tbl_delete_fn()
RETURNS trigger AS '
BEGIN
UPDATE schema.tbl SET deleted=true WHERE ctid=OLD.ctid;
RETURN NULL;
END; ' language plpgsql;
Or...
CREATE RULE delete_rule
AS ON DELETE TO schema.tbl
DO INSTEAD NOTHING;
Pros: Clearer, no code is called for each row visited, and no SP required.
Cons: Less standard than the trigger solution.