简体   繁体   中英

Postgresql Trigger to insert rows


I'm stuck for days with triggers on Postgresql (and Mysql as well). I just want to insert newly filled rows to another table. The original data comes from an external form (OpenDataKit) and goes to "intermediate" tables. I can't understand why the form cannot send the data anymore once the trigger is created... Note that all actions work without the trigger, when I do the insertions by hand. I would greatly appreciate some help to understand what I am doing wrong.
I am now testing with Postgresql 9.5, but I got similar issue with MySQL 5.1.

-- CREATE procedure: 
CREATE OR REPLACE FUNCTION proc_natobs() RETURNS TRIGGER AS
$BODY$
DECLARE
BEGIN
INSERT INTO lieu (id_lieu, wgs_lat, wgs_lon, date_obs, geom)    
    SELECT  id_loc,"GPS_TEL_LAT", "GPS_TEL_LNG", "DATE_OBS", ST_SetSRID(ST_POINT("GPS_TEL_LNG","GPS_TEL_LAT"), 4326)
    FROM "FORMULAIRE_NATOBS_REPEAT_LOC", "FORMULAIRE_NATOBS_CORE"
    WHERE "FORMULAIRE_NATOBS_CORE"."_URI" = "FORMULAIRE_NATOBS_REPEAT_LOC"."_TOP_LEVEL_AURI"
    AND "FORMULAIRE_NATOBS_REPEAT_LOC".id_loc IN (SELECT max(id_loc) FROM "FORMULAIRE_NATOBS_REPEAT_LOC");

INSERT INTO i_lieu_observateurs (id_lieu, id_auteur)
    SELECT id_loc, CAST("AUTEUR" AS integer) 
    FROM "FORMULAIRE_NATOBS_CORE", "FORMULAIRE_NATOBS_REPEAT_LOC"
    WHERE "FORMULAIRE_NATOBS_REPEAT_LOC"."_TOP_LEVEL_AURI" = "FORMULAIRE_NATOBS_CORE"."_URI"
     AND id_loc IN (SELECT max(id_loc) FROM "FORMULAIRE_NATOBS_REPEAT_LOC")
    UNION 
    SELECT id_loc, CAST("OBSERVATEURS" AS integer) 
    FROM "FORMULAIRE_NATOBS_REPEAT_LOC", "FORMULAIRE_NATOBS_REPEAT_OBSERVATEUR"
    WHERE "FORMULAIRE_NATOBS_REPEAT_LOC"."_TOP_LEVEL_AURI" = "FORMULAIRE_NATOBS_REPEAT_OBSERVATEUR"."_TOP_LEVEL_AURI"
    AND id_loc IN (SELECT max(id_loc) FROM "FORMULAIRE_NATOBS_REPEAT_LOC")
    ;
END;
$BODY$
LANGUAGE 'plpgsql';

-- CREATE the trigger:
CREATE TRIGGER trigger_natobs AFTER INSERT
ON "FORMULAIRE_NATOBS_REPEAT_LOC"
FOR EACH ROW
EXECUTE PROCEDURE proc_natobs();

So, when the ODK form inserts new rows in FORMULAIRE_NATOBS_REPEAT_LOC (for which I have created a serial ID to facilitate the SQL queries), I try to insert this row (combined with information from other intermediate tables) into table "lieu" for the first action of the trigger, and into table i_lieu_observation (composed by a double primary key) for the second action. I tested also with a trigger composed by the first action only, but it does not work either. The Android app that sends the form crashes until I remove the trigger.
Thanks in advance!

You need to use the special NEW variable in the trigger to access the newly inserted data. So you need something like:

CREATE OR REPLACE FUNCTION proc_natobs() RETURNS TRIGGER AS
$BODY$
DECLARE
BEGIN
INSERT INTO lieu (id_lieu, wgs_lat, wgs_lon, date_obs, geom)    
    SELECT  new.id_loc,"GPS_TEL_LAT", "GPS_TEL_LNG", "DATE_OBS", ST_SetSRID(ST_POINT("GPS_TEL_LNG","GPS_TEL_LAT"), 4326)
    FROM "FORMULAIRE_NATOBS_CORE"
    WHERE "FORMULAIRE_NATOBS_CORE"."_URI" = new."_TOP_LEVEL_AURI";

INSERT INTO i_lieu_observateurs (id_lieu, id_auteur)
    SELECT new.id_loc, CAST("AUTEUR" AS integer) 
    FROM "FORMULAIRE_NATOBS_CORE"
WHERE new."_TOP_LEVEL_AURI" = "FORMULAIRE_NATOBS_CORE"."_URI"
    UNION 
    SELECT new.id_loc, CAST("OBSERVATEURS" AS integer) 
    FROM "FORMULAIRE_NATOBS_REPEAT_OBSERVATEUR"
    WHERE new."_TOP_LEVEL_AURI" = "FORMULAIRE_NATOBS_REPEAT_OBSERVATEUR"."_TOP_LEVEL_AURI";
RETURN new;
END;
$BODY$
LANGUAGE 'plpgsql';

-- CREATE the trigger:
CREATE TRIGGER trigger_natobs AFTER INSERT
ON "FORMULAIRE_NATOBS_REPEAT_LOC"
FOR EACH ROW
EXECUTE PROCEDURE proc_natobs();

Because I don't know which fields come from which tables, I cannot make the above totally correct. In the same way as I have written new.id_loc, you will need to put new.field_name for all fields coming from the formulaire_natobs_repeat_loc table.

HTH

Try this

CREATE OR REPLACE FUNCTION proc_natobs() RETURNS TRIGGER AS
$BODY$

BEGIN

IF(TG_OP = 'INSERT') THEN

INSERT INTO lieu (id_lieu, wgs_lat, wgs_lon, date_obs, geom)    
    SELECT  id_loc,"GPS_TEL_LAT", "GPS_TEL_LNG", "DATE_OBS", ST_SetSRID(ST_POINT("GPS_TEL_LNG","GPS_TEL_LAT"), 4326)
    FROM "FORMULAIRE_NATOBS_REPEAT_LOC" loc, "FORMULAIRE_NATOBS_CORE" core
    WHERE core."_URI" = loc."_TOP_LEVEL_AURI"
    AND loc.id_loc =new.id_loc;

INSERT INTO i_lieu_observateurs (id_lieu, id_auteur)
    SELECT id_loc as id, 
    CAST("AUTEUR" AS integer)  as auteur
    FROM "FORMULAIRE_NATOBS_CORE" core, "FORMULAIRE_NATOBS_REPEAT_LOC" loc
    WHERE loc."_TOP_LEVEL_AURI" = core."_URI"
     AND loc.id_loc =new.id_loc;
    UNION 
    SELECT id_loc as id, 
    CAST("OBSERVATEURS" AS integer) as auteur
    FROM "FORMULAIRE_NATOBS_REPEAT_LOC" loc, "FORMULAIRE_NATOBS_REPEAT_OBSERVATEUR" obs
    WHERE loc."_TOP_LEVEL_AURI" = obs."_TOP_LEVEL_AURI"
    AND loc.id_loc =new.id_loc;
    END IF;

   Return new;  
END;
$BODY$
LANGUAGE 'plpgsql';

-- CREATE the trigger:
CREATE TRIGGER trigger_natobs AFTER INSERT
ON "FORMULAIRE_NATOBS_REPEAT_LOC"
FOR EACH ROW
EXECUTE PROCEDURE proc_natobs();

Hope it work for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM