Могу ли я использовать возвращаемое значение INSERT ... RETURNING в другом INSERT? - PullRequest
64 голосов
/ 03 июля 2011

Возможно ли что-то подобное?

INSERT INTO Table2 (val)
VALUES ((INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id));

как использовать возвращаемое значение в качестве значения для вставки строки во вторую таблицу со ссылкой на первую таблицу?

Ответы [ 6 ]

76 голосов
/ 03 июля 2011

Вы можете сделать это, начиная с Postgres 9.1:

with rows as (
INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id
)
INSERT INTO Table2 (val)
SELECT id
FROM rows

Между тем, если вас интересует только идентификатор, вы можете сделать это с помощью триггера:

create function t1_ins_into_t2()
  returns trigger
as $$
begin
  insert into table2 (val) values (new.id);
  return new;
end;
$$ language plpgsql;

create trigger t1_ins_into_t2
  after insert on table1
for each row
execute procedure t1_ins_into_t2();
46 голосов
/ 16 октября 2014

Лучшая практика для этой ситуации.Используйте RETURNING … INTO.

INSERT INTO teams VALUES (...) RETURNING id INTO last_id;
8 голосов
/ 07 ноября 2016

В соответствии с ответом, данным Денисом де Бернарди.

Если вы хотите, чтобы id также возвращался после этого, и хотите добавить больше данных в таблицу 2:

with rows as (
INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id
)
INSERT INTO Table2 (val, val2, val3)
SELECT id, 'val2value', 'val3value'
FROM rows
RETURNING val
7 голосов
/ 03 июля 2011

Вы можете использовать функцию lastval():

Возвращаемое значение, полученное последним с nextval для любой последовательности

Так что-то вроде этого:

INSERT INTO Table1 (name) VALUES ('a_title');
INSERT INTO Table2 (val)  VALUES (lastval());

Это будет работать нормально, пока никто не вызовет nextval() для любой другой последовательности (в текущем сеансе) между вашими INSERT.

Как указано Денис ниже, а я предупреждал о вышеизложенном, использование lastval() может вызвать проблемы, если к другой последовательности обращаются, используя nextval() между вашими INSERT. Это может произойти, если в Table1 был триггер INSERT, который вручную вызвал nextval() в последовательности или, что более вероятно, INSERT в таблице с первичным ключом SERIAL или BIGSERIAL , Если вы хотите быть действительно параноиком (хорошая вещь, они на самом деле вы, чтобы получить вас в конце концов), тогда вы можете использовать currval(), но вам нужно знать название соответствующей последовательности:

INSERT INTO Table1 (name) VALUES ('a_title');
INSERT INTO Table2 (val)  VALUES (currval('Table1_id_seq'::regclass));

Автоматически сгенерированная последовательность обычно называется t_c_seq, где t - это имя таблицы, а c - это имя столбца, но вы всегда можете узнать, зайдя в psql и сказав:

=> \d table_name;

и затем поиск значения по умолчанию для рассматриваемого столбца, например:

id | integer | not null default nextval('people_id_seq'::regclass)

К вашему сведению: lastval() является более или менее PostgreSQL-версией MySQL LAST_INSERT_ID. Я упоминаю об этом только потому, что многие люди лучше знакомы с MySQL, чем с PostgreSQL, поэтому ссылка lastval() на что-то знакомое может прояснить ситуацию.

3 голосов
/ 24 апреля 2018
DO $$
DECLARE tableId integer;
BEGIN
  INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id INTO tableId;
  INSERT INTO Table2 (val) VALUES (tableId);
END $$;

Протестировано с помощью psql (10.3, сервер 9.6.8)

0 голосов
/ 30 июля 2016

table_ex

идентификатор по умолчанию nextval ('table_id_seq' :: regclass),

camp1 varchar

camp2 varchar

INSERT INTO table_ex(camp1,camp2) VALUES ('xxx','123') RETURNING id 
...