Триггер PostgreSQL ничего не возвращает - PullRequest
5 голосов
/ 31 октября 2011

У меня есть триггер PostgreSQL при создании, который в основном перенаправляет вставки в вложенные таблицы.Вставив запись, я хочу отменить запрос, чтобы избежать дублирования данных.Единственный способ (который я знаю) сделать это - вернуть NULL в триггер.Проблема в том, что мне нужно вернуть запись, чтобы я мог получить идентификатор.Если я возвращаю NULL, я получаю ... NULL.

Любая идея о том, как я могу иметь триггер, прерывающий операцию, при этом возвращая что-то отличное от NULL?

1 Ответ

5 голосов
/ 31 октября 2011

Ваш вопрос оставляет место для толкования. Насколько я понимаю, вы хотите, чтобы предложение RETURNING команды INSERT возвращало значение первичного ключа, сгенерированного последовательностью.

Есть и другие способы достижения этого. Например, используя nextval(), чтобы заранее получить следующий id из последовательности и вставить строку с прописной id.
ИЛИ currval() / lastval(), чтобы получить последнее полученное значение для последовательности / любой последовательности в текущем сеансе. Больше в этом связанном ответе:
PostgreSQL следующее значение последовательностей?

Вы также можете использовать RULE ... INSTEAD .. для этой цели.

Но, чтобы ответить на ваш вопрос - если это на самом деле ваш вопрос: это можно сделать, используя два триггера . Один BEFORE, один AFTER INSERT. Оба запускаются в одной транзакции для каждого определения, поэтому фантомная строка в вашей первой таблице никогда не видна никому (кроме триггеров).

Демо-версия:

CREATE TABLE x (
  id serial PRIMARY KEY  -- note the serial col.
 ,name text
);

CREATE TABLE y (
  id integer PRIMARY KEY
 ,name text
);


CREATE OR REPLACE FUNCTION trg_x_insbef()
  RETURNS trigger AS
$func$
BEGIN
  INSERT INTO y SELECT (NEW).*;  -- write to other table
  RETURN NEW;
END
$func$ LANGUAGE plpgsql;

CREATE TRIGGER insbef
  BEFORE INSERT ON x
  FOR EACH ROW EXECUTE PROCEDURE trg_x_insbef();


CREATE OR REPLACE FUNCTION trg_x_insaft()
  RETURNS trigger AS
$func$
BEGIN
  DELETE FROM x WHERE id = NEW.id; -- delete row again.
  RETURN NULL;
END
$func$ LANGUAGE plpgsql;

CREATE TRIGGER insaft
  AFTER INSERT ON x
  FOR EACH ROW EXECUTE PROCEDURE trg_x_insaft();

Позвоните в psql:

db=# INSERT INTO x (name) values('phantom') RETURNING id;
 id
----
  1
(1 row)

INSERT 0 1

db=# SELECT * FROM x;
 id | name
----+------
(0 rows)


db=# SELECT * FROM y;
 id |  name
----+---------
  1 | phantom
(1 row)
...