Bounding box not working well in trigger postgresql - postgis - postgresql

My Trigger function consists of collecting the vertices of a polyline table "depart_bt", searching for the point entities of the table “support_bt” which coincide with the vertices of the depart_bt table, then retrieving the value of the "code_dep" attribute (unique identifier of the depart_bt table) of each entity found and report it in the "code_dep" attribute (foreign key in the support_bt table).
CREATE OR REPLACE FUNCTION vertex_troncon() RETURNS TRIGGER
language plpgsql AS
$$
DECLARE
box_pt geometry(point);
BEGIN
IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
IF NEW.code_dep IS NOT NULL THEN
UPDATE support_bt SET code_dep = NEW.code_dep WHERE support_bt.geom_point IN (SELECT (ST_DumpPoints(NEW.geom_line)).geom);
RETURN NULL;
END IF;
ELSE
RAISE WARNING 'Other action occurred: %, at %', TG_OP, now();
RETURN NULL;
END IF;
END;
$$
;
-- creation du trigger
DROP TRIGGER IF EXISTS vertex_dep ON depart_bt;
CREATE TRIGGER vertex_dep AFTER INSERT OR UPDATE ON depart_bt FOR EACH ROW EXECUTE PROCEDURE vertex_troncon();
My first code works well, but it has the disadvantage of iterating through all points of "support_bt" which may affect the performance of the trigger. So, I added a bounding box to limit the search area. However, I noticed that the bounding box does not work fine and all points in the support_bt table are selected.
/*UPDATE support_bt SET code_dep = NEW.code_dep WHERE support_bt.geom_point IN (SELECT (ST_DumpPoints(NEW.geom_line)).geom);*/
SELECT geom_point INTO box_pt FROM support_bt WHERE ST_contains((SELECT ST_SetSRID(ST_Extent(NEW.geom_line),32632)), support_bt.geom_point);
UPDATE support_bt SET code_dep = NEW.code_dep WHERE box_pt IN (SELECT (ST_DumpPoints(NEW.geom_line)).geom);
Thank you in advance for your help.

Related

PostgreSQL trigger: first condition executes but not the second

A trigger works on the first part of a function but not the second.
I'm trying to set up a trigger that does two things:
Update a field - geom - whenever the fields lat or lon are updated, using those two fields.
Update a field - country - from the geom field by referencing another table.
I've tried different syntaxes of using NEW, OLD, BEFORE and AFTER conditions, but whatever I do, I can only get the first part to work.
Here's the code:
CREATE OR REPLACE FUNCTION update_geometries()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
update schema.table a set geom = st_setsrid(st_point(a.lon, a.lat), 4326);
update schema.table a set country = b.name
from reference.admin_layers_0 b where st_intersects(a.geom,b.geom)
and a.pk = new.pk;
RETURN NEW;
END;
$$;
CREATE TRIGGER
geom_update
AFTER INSERT OR UPDATE of lat,lon on
schema.table
FOR EACH STATEMENT EXECUTE PROCEDURE update_geometries();
There is no new on a statement level trigger. (well, there is, but it is always Null)
You can either keep the statement level and update the entire a table, i.e. remove the and a.pk = new.pk, or, if only part of the rows are updated, change the trigger for a row-level trigger and only update the affected rows
CREATE OR REPLACE FUNCTION update_geometries()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
NEW.geom = st_setsrid(st_point(NEW.lon, NEW.lat), 4326);
SELECT b.name
INTO NEW.country
FROM reference.admin_layers_0 b
WHERE st_intersects(NEW.geom,b.geom);
RETURN NEW;
END;
$$;
CREATE TRIGGER
geom_update
BEFORE INSERT OR UPDATE of lat,lon on
schema.table
FOR EACH ROW EXECUTE PROCEDURE update_geometries();

postgresql - trigger function with condition

I'm trying to create a trigger with a condition. Based on the geom length I want the attribute "nom" (= name) to be written in upper case or lower case.
here's what I have:
CREATE OR REPLACE FUNCTION public.test_upper_lower()
RETURNS trigger AS
$BODY$
BEGIN
NEW.dummy:= (ST_Length(new.geom));
if (SELECT dummy FROM ligne_ligne)>100
then NEW.nom:= LOWER(nom) FROM ligne_ligne;
else NEW.nom:= UPPER(nom) FROM ligne_ligne;
end if;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
DROP trigger IF EXISTS test_upper_lower on public.ligne_ligne;
CREATE trigger test_upper_lower BEFORE INSERT OR UPDATE on public.ligne_ligne
FOR EACH ROW
EXECUTE PROCEDURE public.test_upper_lower();
With this I have a "more than one row returned by a subquery" error
Based on other questions on this forum I tried it using case instead of if and using when in the trigger itself not the function but neither are working
Any ideas ?
Thanks
You don't need (or can actually) use SELECT statements to access data from the inserted row.
The part SELECT dummy FROM ligne_ligne returns all rows from that table - not just from the one relevant to the trigger.
As you just want to check the value you just calculated, simply use new.dummy at that point:
CREATE OR REPLACE FUNCTION public.test_upper_lower()
RETURNS trigger AS
$BODY$
BEGIN
NEW.dummy:= ST_Length(new.geom);
if new.dummy > 100 then --<< no SELECT necessary
NEW.nom:= LOWER(new.nom); --<< no "FROM", just access the value
else
NEW.nom:= UPPER(new.nom);
end if;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;

PSQL Add value from row to another value in the same row using triggers

I have a test table with three columns (file, qty, qty_total). I will input multiple rows like this for example, insert into test_table (file,qty) VALUS (A,5);. What i want is for on commit is for a trigger to take the value from qty and add it to qty_total. As what will happen is that this value will get updated as this example demonstrates. Update test_table set qty = 10 where file = A; So the qty_total is now 15. Thanks
Managed to solve this myself. I created a trigger function `CREATE FUNCTION public.qty_total()
RETURNS trigger
LANGUAGE 'plpgsql'
COST 100.0
VOLATILE NOT LEAKPROOF
AS $BODY$
BEGIN
IF TG_OP = 'UPDATE' THEN
NEW."total" := (OLD.total + NEW.col2);
RETURN NEW;
ELSE
NEW."total" := NEW.col2;
RETURN NEW;
END IF;
END;
$BODY$;
ALTER FUNCTION public.qty_total()
OWNER TO postgres; This was called by a trigger CREATE TRIGGER qty_trigger
BEFORE INSERT OR UPDATE
ON public.test
FOR EACH ROW
EXECUTE PROCEDURE qty_total(); now when i insert a new code and value, the value is copied to the total, when it is updated, the value is added to the total and i have my new qty_total. This may not have the best error catching in it, but since i am passing the data from php, i am happy to make sure the errors are caught and removed.

Using rules in postgresql to insert several rows

I need to insert several rows using a rule.
My problem is:
I draw a poligon and save on a table z0_poligono_corte, then I use a rule to get the intersection between the polygon in z0_poligono_corte and polygons in other table, but the result is not inserted in the table I created to save the results. Also there are no errors in the postgres log.
CREATE RULE cortar_anp AS ON INSERT TO z0_poligono_corte
DO also insert into z0_a_n_p_13 (id_poligono, folio, obs, anp, geometria) select pol.id, pol.folio, pol.obs, capa.anp, ST_Multi(ST_Intersection(capa.geom, pol.geometria))
from a_n_p_13 capa, z0_poligono_corte pol
where pol.id=NEW.id
and capa.geom && pol.geometria
and ST_IsEmpty(ST_Intersection(capa.geom, pol.geometria)) != TRUE;
I don't know if my rule is correct. If I run the insert into sentence using for example pol.id=1 then the result saves correctly.
image
I have not 10 reputation to put the image :(
Here the image
Thanks.
Here is how solved my problem with a trigger.
First i created a table
CREATE TABLE public.z0_poligono_corte (
id serial,
nombre character varying(255),
giro text,
geometria geometry(MultiPolygon,32614),
CONSTRAINT z0_poligono_corte_pkey PRIMARY KEY (id) )
After that I created a trigger function that makes the slice
CREATE OR REPLACE FUNCTION public.cortes_interseccion_amias()
RETURNS trigger AS
$BODY$
declare var_sql text;
begin
var_sql := 'insert into z0_amias08 (id_poligono, nombre, giro, tipo, geometria)
select pol.id, pol.nombre, pol.giro, capa.tipo, ST_Intersection(capa.geom, pol.geometria)
from amias08 capa, z0_poligono_corte pol
where pol.id=$1
and capa.geom && pol.geometria
and ST_IsEmpty(ST_Intersection(capa.geom, pol.geometria)) != TRUE';
execute var_sql using NEW.id;
return NEW;
end;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Then the trigger.
CREATE TRIGGER interseccion_amias
AFTER INSERT
ON public.z0_poligono_corte
FOR EACH ROW
EXECUTE PROCEDURE public.cortes_interseccion_amias();
So when I insert a polygon on that table, the trigger function will cut on the table with data, then insert on the new table

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