Trigger insert of data into table with result from another select query - sql

Starting my first steps in SQL.
I'm trying to insert the last row of a timestamped table to another table.
I've written this trigger:
CREATE TRIGGER update_analysis()
AFTER INSERT ON data
FOR EACH ROW
EXECUTE PROCEDURE insert_to_analysis();
I've defined a function, which I know is wrong, but don't understand how to write it correctly. (the target table has these columns)
CREATE FUNCTION UPDATE_ANALYSIS() RETURNS TABLE
AS
$$ BEGIN
INSERT INTO ANALYSIS (TIME, CYCLE_NUMBER,CAT1,CAT2,CAT3)
SELECT (TIME, CYCLENO , I1 , I2 * 2 ,I3*3)
FROM DATA
ORDER BY TIME DESC
LIMIT 1;)
RETURN
END;
$$ LANGUAGE 'plpgsql';
Thanks in advance

If you are referencing the same data you just inserted into data, you could simply refer to what you inserted instead of SELECT:ing, like so:
CREATE FUNCTION UPDATE_ANALYSIS() RETURNS TABLE
AS
$$ BEGIN
INSERT INTO ANALYSIS (TIME, CYCLE_NUMBER,CAT1,CAT2,CAT3)
VALUES (NEW.TIME, NEW.CYCLENO , NEW.I1 , NEW.I2 * 2 ,NEW.I3 * 3);
RETURN NEW;
END;
$$ LANGUAGE 'plpgsql';

Since it's a function for a trigger, it should return a trigger.
And it's for each row, so an insert from values is possible.
Example
CREATE FUNCTION FN_INSERT_TO_ANALYSIS() RETURNS TRIGGER
AS $ins_analysis$
BEGIN
INSERT INTO ANALYSIS (TIME, CYCLE_NUMBER, CAT1, CAT2, CAT3)
VALUES (NEW.TIME, NEW.CYCLENO, NEW.I1, NEW.I2 * 2 , NEW.I3 * 3);
RETURN NEW;
END $ins_analysis$ LANGUAGE 'plpgsql';
CREATE TRIGGER trg_data_ins_analysis
AFTER INSERT ON data
FOR EACH ROW
EXECUTE PROCEDURE fn_insert_to_analysis();
insert into data values (current_timestamp,1,1,1,1)
select * from data
time
cycleno
i1
i2
i3
2021-12-27 14:53:17.822649
1
1
1
1
select * from ANALYSIS
time
cycle_number
cat1
cat2
cat3
2021-12-27 14:53:17.822649
1
1
2
3
Demo on db<>fiddle here

Related

Trigger function not working in postgresql

I have tables as follows:
test
address
value
a1
50
table1
address
amount
id
hash
a1
50
2
se2
I am trying to add the amount to a1 when a new insertion of a1 is added to the test table i.e. if a new row is added to test i.e. address = a1 and value = 100 then, i want to update the amount in a1 on table1 table i.e. amount = 50 + 100 = 150 but the value does not get updated.
Here is my trigger implementation:
CREATE OR REPLACE FUNCTION address_trigger()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
UPDATE table1
SET amount = amount + new.value
WHERE NEW.address = table1.address;
RETURN NEW;
end;
$$;
CREATE TRIGGER update_table1
AFTER INSERT
ON "test"
FOR EACH ROW
EXECUTE PROCEDURE address_trigger();
I added the trigger function via query console and the trigger function shows on the database as update_table1 in intellij. then, i insert a new row to test manually INSERT INTO test(address, value) VALUES ('a1',100);. the row gets updated on test but the value is not updated on table1 on reloading. Could someone help me out, what am i doing wrong here?
It works ok for me. Create tables
create table "test"(
address varchar(10),
value int
);
create table table1 (
address varchar(10),
amount int
);
insert into table1
values('abc', 0);
Your trigger
CREATE OR REPLACE FUNCTION address_trigger()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
UPDATE table1
SET amount = amount + new.value
WHERE NEW.address = table1.address;
RETURN NEW;
end;
$$;
CREATE TRIGGER update_table1
AFTER INSERT
ON "test"
FOR EACH ROW
EXECUTE PROCEDURE address_trigger();
Test it
insert into "test"
values ('abc', 10),
('abc', 30);
select *
from table1;
Output
address amount
abc 40

How to use a newly inserted value from another table in PostgreSQL?

Assuming I have two tables final table and table_1, I want to use the the newest values from table_1 and insert them with a trigger in the final_table with every INSERT ON table_1. When I create the triggerfunction inserttrigger() as shown in the example and create the trigger, I get the newest value times the number of rows in table_1. How to write the trigger proper that I get only the single newest record in table1?
Doing:
-- Create tables and inserting example values
CREATE TABLE final_table(id INTEGER, value_fin INTEGER);
CREATE TABLE table_1(id INTEGER, value INTEGER);
INSERT INTO table_1 VALUES(1, 200), (2,203), (3, 209);
-- Create Triggerfunction
CREATE OR REPLACE FUNCTION inserttrigger()
RETURNS TRIGGER AS
$func$
BEGIN
INSERT INTO final_table
SELECT latest.id, latest.value
FROM (SELECT NEW.id, NEW.value FROM table_1) AS latest;
RETURN NEW;
END;
$func$ language plpgsql;
-- Create Trigger
CREATE TRIGGER final_table_update BEFORE INSERT ON table_1
FOR EACH ROW EXECUTE PROCEDURE inserttrigger() ;
--Insert example values
INSERT INTO table_1 VALUES(4, 215);
Results in:
SELECT * FROM final_table
id | value_fin
4 215
4 215
4 215
But should look like:
id | value_fin
4 215
While:
CREATE TRIGGER final_table_update BEFORE INSERT ON table_1
EXECUTE PROCEDURE inserttrigger() ;
Results in:
ERROR: record "new" is not assigned yet
DETAIL: The tuple structure of a not-yet-assigned record is indeterminate.
I would recommend the VALUES() syntax:
CREATE OR REPLACE FUNCTION inserttrigger()
RETURNS TRIGGER AS
$func$
BEGIN
INSERT INTO final_table VALUES(NEW.id, NEW.value);
RETURN NEW;
END;
$func$ language plpgsql;
CREATE TRIGGER final_table_update BEFORE INSERT ON table_1
FOR EACH ROW EXECUTE PROCEDURE inserttrigger();
Note that you could also get the same behavior with a common-table-expression and the returning syntax, which avoids the need for a trigger:
with t1 as (
insert into table_1(id, value_fin) values(4, 215)
returning id, value_fin
)
insert into final_table(id, value) select id, value_fin from t1

Use Record As Function Argument in RETURNING Statement

I have a plpgsql function that takes a record as an argument.
I would like to call this function in the RETURNING statement of an insert, but am unsure what to put as the argument (* does not work) i.e.,
-- Postgres 12
INSERT INTO some_table (a, b, c)
VALUES .....
RETURNING
function_that_takes_record_argument(<the_new_record>)
What can I use in place of <the_new_record>?
To pass a record/row to a function you need to explicitly specify the record type:
create table t(a int, b text);
create or replace function f(r record) returns int language plpgsql as $$
begin
return r.a;
end $$;
insert into t values(2, 'b');
select f(t.*), f(t), f((a,b)::t) from t;
f | f | f
---+---+---
2 | 2 | 2
insert into t values(3, 'c') returning f(t);
f
---
3
I am unsure why your example does not work, but I would try a data-modifying CTE:
WITH insert_result AS (
INSERT INTO ... RETURNING *
)
SELECT your_function_here(insert_result.*)
See more at https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-MODIFYING

plpgsql how to insert results of query into table?

I have a query A returning values integer, numeric, integer.
and a table B:
(id integer,
weight numeric,
price integer
)
the query returns many rows. I want to insert those rows directly to B. B doesn't have nor need a PK...
CREATE OR REPLACE FUNCTION func()
RETURNS void AS
$BODY$
begin
query A
insert to B?
continue function operation
end;
$BODY$
LANGUAGE plpgsql VOLATILE
I know it something like:
for row in query A
loop insert into B
but I can't find the proper syntax
You would do something like:
insert into b(id, weight, price)
select id, weight, price -- or whatever the column names are
from A;
The syntax of insert . . . select doesn't change because you are in a function.

Postgresql insert trigger does not work

New row is added to table A and i need trigger which will automatically insert row in table B after row has been inserted in table A.
CREATE FUNCTION insertblocked (
)
RETURNS trigger AS
$body$
BEGIN
INSERT INTO tableB (blocked.id,blocked.number,blocked.date)
VALUES (new.id,new.prefix,now())
RETURN NEW;
END
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER;
CREATE TRIGGER insertblocked
AFTER INSERT
ON public.tableA FOR EACH ROW
EXECUTE PROCEDURE insertblocked();
Please help and advise, why is sql compiler returning and error
QUERY: INSERT INTO blocked (blocked.id,blocked.number,blocked.date) VALUES ( $1 , $2 ,now()) RETURN $3
You're missing a semi-column ; at the end of your insert statement.