HSQLDB DECLARE ROW IN A TRIGGER - triggers

Hi all I try to get a row form my select statemnt in a trigger but I got this error unexpected token: R
CREATE TRIGGER PUBLIC.TRIGGERNAME AFTER UPDATE ON PUBLIC.CLIENTE_OFFERENTE
REFERENCING NEW ROW AS NUOVO
FOR EACH ROW
BEGIN ATOMIC
DECLARE r RECORD;
SET r=(SELECT offerta.IDIMMOBILE as ID, immobile.prezzomax as costo FROM PUBLIC.OFFERTA join immobile on immobile.idImmobile=offerta.idImmobile WHERE IDOFFERTA=NUOVO.IDOFFERTA);
IF NUOVO.STATO='Venduto'THEN
INSERT INTO PUBLIC.VENDITE(IDCLIENTE,IDIMMOBILE,COSTO)VALUES(NUOVO.IDCLIENTE,r.ID,r.costo);
END IF;
END

You cannot DECLARE a variable of RECORD type.
You want to get two values from your select statement. Therefore you need to declare two variables.
BEGIN ATOMIC
DECLARE VAR_ID INT;
DECLARE VAR_COSTO INT;
SET (VAR_ID, VAR_COSTO) =(SELECT offerta.IDIMMOBILE as ID, immobile.prezzomax as costo FROM PUBLIC.OFFERTA join immobile on immobile.idImmobile=offerta.idImmobile WHERE IDOFFERTA=NUOVO.IDOFFERTA);
IF NUOVO.STATO='Venduto'THEN
INSERT INTO PUBLIC.VENDITE(IDCLIENTE,IDIMMOBILE,COSTO)VALUES(NUOVO.IDCLIENTE,VAR_ID,VAR_COSTO);
END IF;
END

Related

How do I integrate a FOR loop into my dynamic queries?

I am trying to run a dynamic query. I have a static query that works :
CREATE OR REPLACE
FUNCTION update_points_in_polygon(
)
RETURNS trigger LANGUAGE plpgsql AS $function$
-- Rule for clarity : one filter per function. Can choose three options : point count unit count and label concat
-- the one rule will be applied to all 3 options if they are selected
DECLARE tmprow record;
BEGIN
FOR tmprow IN
SELECT c.objectid, count(a.*) point_count
FROM sandbox.simple_address a
JOIN sandbox.polygon_address_units c
ON st_intersects(a.wkb_geometry, c.wkb_geometry)
WHERE st_intersects(c.wkb_geometry, NEW.wkb_geometry)
GROUP BY c.objectid -- tmp TABLE fetchin nb OF addresses IN a polygon WHERE polygon interects point
LOOP
UPDATE sandbox.polygon_address_units
SET address_count = tmprow.point_count
WHERE objectid = tmprow.objectid; -- UPDATE point_count COLUMN OF TABLES fetched IN FIRST SELECT
END LOOP;
RETURN NEW;
END;
$function$;
When I try to replace the loop like this :
EXECUTE 'FOR tmprow IN
SELECT c.objectid, count(a.*) point_count
FROM sandbox.simple_address a
JOIN sandbox.polygon_address_units c
ON st_intersects(a.wkb_geometry, c.wkb_geometry)
WHERE st_intersects(c.wkb_geometry, NEW.wkb_geometry)
GROUP BY c.objectid
LOOP
UPDATE sandbox.polygon_address_units
SET address_count = tmprow.point_count
WHERE objectid = tmprow.objectid;
END LOOP;';
I get the following message :
SQL Error [42601]: ERROR: syntax error at or near "FOR" Where:
PL/pgSQL function update_points_in_polygon() line 7 at EXECUTE
The aim is to be able to define table_names and columns dynamically. I've also tried to make two execute statements and keep the LOOP in plpgsql instead of plain SQL that's run with EXECUTE:
CREATE OR REPLACE
FUNCTION update_points_in_polygon(
)
RETURNS trigger LANGUAGE plpgsql AS $function$
-- Rule for clarity : one filter per function. Can choose three options : point count unit count and label concat
-- the one rule will be applied to all 3 options if they are selected
DECLARE tables_schema varchar;
DECLARE polygon_table_name varchar;
DECLARE polygon_point_count_column_name varchar;
DECLARE point_table_name varchar;
DECLARE tmprow record;
BEGIN
tables_schema = TG_ARGV[0]; -- frontier_ftth
polygon_table_name = TG_ARGV[1]; -- fdh
polygon_point_count_column_name = TG_ARGV[2]; -- point_count
point_table_name = TG_ARGV[4];
FOR tmprow IN
EXECUTE format('SELECT c.objectid, count(a.*) point_count
FROM %I.%I a
JOIN %I.%I c
ON st_intersects(a.wkb_geometry, c.wkb_geometry)
WHERE st_intersects(c.wkb_geometry, st_geomFromText(''%s'', 4326))
GROUP BY c.objectid',
tables_schema, point_table_name, tables_schema, polygon_table_name,
st_astext(st_geomfromewkb(NEW.wkb_geometry)))
LOOP
EXECUTE format('UPDATE %I.%I c1
SET %I = tmprow.point_count
WHERE c1.objectid = tmprow.objectid',
tables_schema, polygon_table_name, polygon_point_count_column_name);
END LOOP;
RETURN NEW;
END;
$function$
With this version of the function, I get the following error :
SQL Error [22004]: ERROR: null values cannot be formatted as an SQL identifier
Where: PL/pgSQL function update_points_in_polygon() line 17 at FOR over EXECUTE statement
This is a barebones version of my setup :
CREATE TABLE sandbox.simple_address (
objectid serial4 NOT NULL,
wkb_geometry geometry(point, 4326) NULL,
);
CREATE TABLE sandbox.polygon_address_units (
objectid serial4 NOT NULL,
address_count int4 NULL,
wkb_geometry geometry(multipolygon, 4326) NULL,
);
CREATE TRIGGER onallactions AFTER INSERT
OR UPDATE ON
sandbox.simple_address FOR EACH ROW
WHEN ((pg_trigger_depth() < 1)) EXECUTE PROCEDURE
update_points_in_polygon(
'sandbox', 'polygon_address_units', 'address_count',
'simple_address');
INSERT INTO sandbox.polygon_address_units(wkb_geometry)
VALUES(ST_SetSRID(st_astext(st_geomfromtext('MULTIPOLYGON (((-1 1, 1 1, 1 -1, -1 -1, -1 1)))')),4326));
INSERT INTO sandbox.simple_address(wkb_geometry)
VALUES(ST_SetSRID(st_astext(st_geomfromtext('POINT(0 0)')),4326));
How do use these two queries to properly update the number_of_points column in my polygon layers when I add a point that intersects it ? There might be multiple polygons to update.
EDIT: The solution was to call tmprow to format the second string
FOR tmprow IN
EXECUTE format('SELECT c.objectid, count(a.*) point_count
FROM %I.%I a
JOIN %I.%I c
ON st_intersects(a.wkb_geometry, c.wkb_geometry)
WHERE st_intersects(c.wkb_geometry, st_geomFromText(''%s'', 4326))
GROUP BY c.objectid',
tables_schema, point_table_name, tables_schema, polygon_table_name,
st_astext(st_geomfromewkb(NEW.wkb_geometry)))
LOOP
EXECUTE format('UPDATE %I.%I c1
SET %I = %s
WHERE c1.objectid = %s ',
tables_schema, polygon_table_name, polygon_point_count_column_name, tmprow.point_count, tmprow.objectid);
END LOOP;
RETURN NEW;
END;
$function$

Set value using select

I am new to using postgresql, I am trying to make a trigger that just inserts in the Employee table and also inserts in the Vacations table, but I don't know how to assign the values, I do it like that in sql but here I really don't know how
CREATE FUNCTION SP_InsertaVacacionesEmpleado() RETURNS TRIGGER
AS
$$
DECLARE _NumeroIdentificacion INTEGER;
DECLARE _FechaEntrada DATE;
BEGIN
SET _NumeroIdentificacion = SELECT NEW.NumeroIdentificacion FROM "Empleado"
SET _FechaEntrada = SELECT NEW.FechaEntrada FROM "Empleado"
INSERT INTO Vacaciones VALUES(_NumeroIdentificacion, _FechaEntrada, '', 0);
RETURN NEW;
END
$$
LANGUAGE plpgsql
As documented in the manual assignment is done using the := operator, e.g.:
some_variable := 42;
However to assign one or more variables from the result of a query, use select into, e.g.:
DECLARE
var_1 INTEGER;
var_2 DATE;
BEGIN
select col1, col2
into var_1, var_2
from some_table
...
However neither of that is necessary in a trigger as you can simply use the reference to the NEW record directly in the INSERT statement:
CREATE FUNCTION sp_insertavacacionesempleado()
RETURNS TRIGGER
AS
$$
BEGIN
INSERT INTO Vacaciones (...)
VALUES (NEW.NumeroIdentificacion, NEW.FechaEntrada , '', 0);
RETURN NEW;
END
$$
LANGUAGE plpgsql;
Note that you need to define a row level trigger for this to work:
create trigger ..
before insert on ...
for each row --<< important!
execute procedure sp_insertavacacionesempleado() ;

stored procedure - pass multiple values for IN clause

I'm writing a stored procedure for Postgres, just do select * from table where id in (value1, value2, ...).
These values will be getting from the variable.
My code:
CREATE OR REPLACE PROCEDURE record_example(v_name varchar(100), v_id int)
LANGUAGE plpgsql
AS $$
DECLARE
rec RECORD;
BEGIN
FOR rec IN select id, updated from mytable where names in (v_name) and id=v_id
LOOP
RAISE INFO 'id = % and updated = %', rec.id, rec.updated;
END LOOP;
END;
$$;
This actually works if I use single value for v_name.
Ex:
call record_example('myname',101);
But if I do multiple values, its not working.
HELP 1 :
call record_example('myname, your_name',101);
It just returned CALL, that's it. Nothing happened.
HELP 2:
Sometimes the v_id variable is optional, so that time the FOR loop should inclue the id=v_id
Ex:
FOR rec IN select id, updated from mytable where names in (v_name)
LOOP
RAISE INFO 'id = % and updated = %', rec.id, rec.updated;
END LOOP;

Trigger after update: How to execute query for every row updated

I wrote trigger to execute a query after the update of the column (retard) in my table, but sometimes there are many rows updated how to solve that?
CREATE OR ALTER TRIGGER notifRetard
ON Taches
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #value INT
IF UPDATE(retard)
-- How to make this for every row updated???
SELECT
#value = inserted.retard
FROM
inserted;
IF #value = 1
-- run SQL query
END
The solution if someone else need it is to use CURSOR.
CREATE or alter TRIGGER notifRetard
ON Taches
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF UPDATE(retard)
begin
DECLARE #RefTache varchar(50),#RefPhase numeric(4,0),#IDprojet varchar(50),#IDressource varchar(50) #retard bit;
DECLARE TrigTempUpdate_Cursor CURSOR FOR
SELECt RefTache,RefPhase,IDprojet,IDressource,retard
FROM
inserted;
begin
OPEN TrigTempUpdate_Cursor;
FETCH NEXT FROM TrigTempUpdate_Cursor INTO #RefTache, #RefPhase,#IDprojet,#IDressource,#retard
WHILE ##FETCH_STATUS = 0
BEGIN
if #retard=1
--DO QUERY HERE
FETCH NEXT FROM TrigTempUpdate_Cursor INTO #RefTache, #RefPhase,#IDprojet,#IDressource,#retard
END;
end;
CLOSE TrigTempUpdate_Cursor;
DEALLOCATE TrigTempUpdate_Cursor;
end;
end;

PL/PGSQL: Store the result of a loop in a table

I want to store the result of the following loop in a table:
DO $$
DECLARE rec RECORD;
BEGIN
FOR rec IN SELECT c1 FROM t1
LOOP
SELECT foo(rec.c1);
END LOOP;
END; $$
LANGUAGE 'plpgsql';
How can I do that?
You don't need a loop for that at all. In fact you don't even need a function for that:
insert into some_table (some_column)
select foo(c1)
from t1
Or if you want to create the table based on the query:
create table_some
as
select foo(c1) as some_column
from t1;