Триггер Postgresql для вставки строк


Я несколько дней застрял с триггерами в Postgresql (и в Mysql тоже). Я просто хочу вставить новые заполненные строки в другую таблицу. Исходные данные поступают из внешней формы (OpenDataKit) и попадают в «промежуточные» таблицы. Я не могу понять, почему форма больше не может отправлять данные после создания триггера... Обратите внимание, что все действия работают без триггера, когда я делаю вставки вручную. Я был бы очень признателен за помощь, чтобы понять, что я делаю неправильно.
Сейчас я тестирую Postgresql 9.5, но у меня возникла аналогичная проблема с 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();

Итак, когда форма ODK вставляет новые строки в FORMULAIRE_NATOBS_REPEAT_LOC (для которых я создал серийный идентификатор для облегчения SQL-запросов), я пытаюсь вставить эту строку (в сочетании с информацией из других промежуточных таблиц) в таблицу «заместо» для первого действие триггера и в таблицу i_lieu_observation (составленную двойным первичным ключом) для второго действия. Я тестировал также с триггером, состоящим только из первого действия, но он тоже не работает. Приложение для Android, отправляющее форму, аварийно завершает работу, пока я не удалю триггер.
Заранее спасибо!


person RemiC    schedule 09.08.2016    source источник
comment
Вместо использования MAX(id_loc) FROM FORMULAIRE_... вы должны использовать new.xxx для проверки строки, вызвавшей срабатывание триггера.   -  person joop    schedule 09.08.2016
comment
Было бы полезно, если бы вы добавили определения для всех упомянутых таблиц в вопрос. Мне кажется, что между двумя таблицами вместо i_lieu_observateurs существует отношение 1:N. И это, безусловно, помогло бы, если бы вы использовали синтаксис JOIN.   -  person wildplasser    schedule 10.08.2016


Ответы (2)


Вам нужно использовать специальную переменную NEW в триггере для доступа к вновь вставленным данным. Итак, вам нужно что-то вроде:

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

Поскольку я не знаю, какие поля берутся из каких таблиц, я не могу сделать вышеизложенное полностью правильным. Точно так же, как я написал new.id_loc, вам нужно будет поставить new.field_name для всех полей, поступающих из таблицы Formulaire_natobs_repeat_loc.

ХТН

person Community    schedule 09.08.2016
comment
Спасибо, но это не сработало. Но посмотрите мой комментарий к @Paarth - person RemiC; 09.08.2016
comment
Я так понимаю, что FORMULAIRE_NATOBS_CORE и FORMULAIRE_NATOBS_REPEAT_OBSERVATEUR действительно имеют значения, соответствующие новому.TOP_LEVEL_AURI? - person ; 09.08.2016
comment
Спасибо за вашу помощь. К сожалению, пока не работает, приложение вылетает. Однако, когда я смешиваю ваш сценарий со сценарием Paarth, то есть добавляю IF(TG_OP = 'INSERT') THEN .... END IF, форма действительно отправляет данные, но это похоже на то, что триггер ничего не запускает. У вас есть идея? Да, связь между таблицами ODK — это _CORE._URI = _REPEAT_OBSERVAEUR._TOP_LEVEL_AURI = _REPEAT_LOC._TOP_LEVEL_AURI с одной строкой в ​​_CORE, которая может быть связана с несколькими строками в таблицах LOC и OBSERVATEUR. - person RemiC; 09.08.2016
comment
IF (TG_OP и т. д. не требуется, если функция вызывается только после вставки. Пробовали ли вы добавить строку вручную в pgadmin? Не могли бы вы опубликовать какое-либо сообщение об ошибке? Также я предполагаю, что у вас есть вставка db в попытке .. catch. Что Выбрасывается исключение? - person ; 10.08.2016
comment
На самом деле, это хороший момент. Когда я вставляю строку вручную, триггер работает! Я начинаю с заполнения _CORE и _OBSERVATEUR перед _LOC, чтобы триггер мог что-то вернуть. Поэтому мне интересно, возможно ли, чтобы форма ODK отправляла строки последовательно, начиная, например, с таблицы _LOC, чтобы триггер работал, но возвращал NULL, поскольку _CORE и _OBSERVATEUR все еще пусты в это время? - person RemiC; 10.08.2016
comment
Это тоже было мое предположение! К сожалению, я не пользуюсь ODK, поэтому ничем помочь не могу. Я предлагаю вам открыть новый вопрос о том, как обеспечить последовательное обновление таблиц ODK и пометить триггер как ответ (потому что триггер явно работает!). Надеюсь, вы привлечете другой набор ответов. - person ; 10.08.2016

Попробуй это

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

Надеюсь, это сработает для вас.

person Paarth    schedule 09.08.2016
comment
Спасибо! Идет лучше в том смысле, что форма теперь заполняет таблицы FORMULAIRE_xx ОДК, но триггер ничего не возвращает. Столы lieu и i_lieu_observateurs пока пусты... У вас есть какие-нибудь дополнительные советы, пожалуйста? - person RemiC; 09.08.2016
comment
Проверьте, включен ли триггер. Если триггер включен и в триггере есть какая-либо ошибка, таблица "FORMULAIRE_NATOBS_REPEAT_LOC" также не будет заполнена. проверить триггер. - person Paarth; 10.08.2016
comment
Если триггер в порядке, попробуйте вставить запрос с некоторыми фиктивными данными для таблиц вместо и i_lieu_observateurs. Вставка работает или нет для данных таблиц. - person Paarth; 10.08.2016