我可以在另一个INSERT中使用INSERT…RETURNING的返回值吗?


86

这样的事情可能吗?

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

像使用返回值作为值在第二张表中插入对第一张表的引用的行?

Answers:


103

您可以从Postgres 9.1开始:

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

同时,如果您仅对ID感兴趣,则可以使用触发器进行操作:

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

1
如何在返回ID旁边插入值?例如:INSERT INTO TABLE2(val1,val2,val3)(1、2,SELECT id FROM rows)
Mahmoud Hanafy 2016年

@MahmoudHanafy:替换rows(some_query returning ...)现在可能有效(尚未尝试)。
Denis de Bernardy

2
@MahmoudHanafy:要在返回的ID旁边插入值,您可以执行以下操作:INSERT INTO TABLE2(val1,val2,val3)SELECT id,1,2 FROM rows
Bhindi 2016年

赞!如果第一次插入成功而第二次插入没有发生,那么这个原子含义是什么?
PirateApp

2
@PirateApp刚刚测试!v12.4。如果第二个INSERT失败,则确实会回滚第一个INSERT,但是会跳过第一个INSERT的序列/自动增量
Madacol


13

符合丹尼斯·德·伯纳迪(Denis de Bernardy)的回答。

如果您还希望随后返回ID,并希望在Table2中插入更多内容:

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

10
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)


8

您可以使用以下lastval()功能:

nextval对于任何序列,最近获得的返回值

所以像这样:

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

只要没有人nextval()在您的INSERT之间调用任何其他序列(在当前会话中),此方法就可以正常工作。

正如Denis在下面指出的,而我在上面已经警告过,lastval()如果nextval()在INSERT之间使用另一个序列访问,使用会使您陷入麻烦。如果在序列上Table1手动调用了INSERT触发器,nextval()或者更可能是在具有SERIALBIGSERIAL主键的表上进行了INSERT,则可能发生这种情况。如果您真的想变得偏执(好东西,毕竟他们真的是您要带您去),那么您可以使用,currval()但您需要知道相关序列的名称:

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

自动生成的序列通常被命名为t_c_seqwheret是表名和c列名,但是您始终可以通过输入以下内容找出psql答案:

=> \d table_name;

然后查看相关列的默认值,例如:

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

仅供参考:lastval()或多或少是MySQL的PostgreSQL版本LAST_INSERT_ID。我之所以仅提及这一点,是因为许多人比PostgreSQL对MySQL更熟悉,因此链接lastval()到熟悉的事物可能会澄清一些事情。


2
不过,最好使用currval(),以防table1上的触发器执行后续插入操作。
Denis de Bernardy 2011年

@Denis:是的,但是您需要序列的名称。我将对此效果进行一些更新,以涵盖所有基础。
亩太短了,

LASTVAL()和CURRVAL()都适用于当前数据库连接,不适用于其他连接。其他用户可以同时更新序列,这不会改变您的结果。不必担心其他人,他们将永远不会更改LASTVAL和/或CURRVAL的结果。如果在没有事务的情况下使用连接池,则根本无法使用LASTVAL和CURRVAL,这就是当事情出错时:您无法控制数据库连接。
Frank Heikens 2011年

1
@Frank:是的,它们都是特定于会话的,但是问题lastval是在Table1的AFTER INSERT触发器后面可能有基于序列的INSERT。那将在当前会话中,并且可能会lastval()在您不期望的时候发生变化。
亩太短了,

1

table_ex

id默认为nextval('table_id_seq':: regclass),

camp1 varchar

camp2 varchar

INSERT INTO table_ex(camp1,camp2) VALUES ('xxx','123') RETURNING id 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.