从Posgtres批量插入返回多个SERIAL值

Nic*_*las 6 postgresql

我正在使用Postgres SERIAL作为我的主键.插入一行后,我可以使用' RETURNING'或'获取生成的密钥CURRVAL().

现在我的问题是我想在事务中进行批量插入并获取所有生成的密钥.

所有我得到的RETURNING并且CURRVAL是最后生成的id,结果的其余部分被丢弃.

我怎样才能让它归还所有这些?

谢谢

mu *_*ort 21

您可以使用RETURNING多个值:

psql=> create table t (id serial not null, x varchar not null);
psql=> insert into t (x) values ('a'),('b'),('c') returning id;
 id 
----
  1
  2
  3
(3 rows)
Run Code Online (Sandbox Code Playgroud)

所以你想要更像这样的东西:

INSERT INTO AutoKeyEntity (Name,Description,EntityKey) VALUES
('AutoKey 254e3c64-485e-42a4-b1cf-d2e1e629df6a','Testing 5/4/2011 8:59:43 AM',DEFAULT)
returning EntityKey;
INSERT INTO AutoKeyEntityListed (EntityKey,Listed,ItemIndex) VALUES
(CURRVAL('autokeyentity_entityKey_seq'),'Test 1 AutoKey 254e3c64-485e-42a4-b1cf-d2e1e629df6a', 0),
(CURRVAL('autokeyentity_entityKey_seq'),'Test 2 AutoKey 254e3c64-485e-42a4-b1cf-d2e1e629df6a', 1),
(CURRVAL('autokeyentity_entityKey_seq'),'Test 3 AutoKey 254e3c64-485e-42a4-b1cf-d2e1e629df6a', 2)
returning EntityKey;
-- etc.
Run Code Online (Sandbox Code Playgroud)

然后,您必须EntityKey从事务中的每个语句中收集返回的值.

您可以尝试在事务的开始和结束时获取序列的当前值,并使用它们来确定使用了哪些序列值但不可靠:

此外,尽管保证多个会话分配不同的序列值,但是当考虑所有会话时,可能不按顺序生成值.例如,如果 缓存设置为10,则会话A可能会保留值1..10并返回 nextval=1,然后会话B可能会保留值11..20并nextval=11在会话A生成nextval = 2之前返回 .因此,如果 缓存设置为1,则可以安全地假设nextval值是按顺序生成的; 如果缓存设置大于1,您应该只假设这些nextval值都是不同的,而不是纯粹按顺序生成它们.此外,last_value还将反映任何会话保留的最新值,无论该会话是否尚未返回nextval.

因此,即使您的序列的缓存值为1,您仍可在事务中使用非连续的序列值.但是,如果序列的缓存值与事务中INSERT的数量相匹配,那么您可能会安全,但我猜这会太大而无法理解.

更新:我刚刚注意到(感谢提问者的评论),涉及两个表,在文本墙中有点丢失.

在这种情况下,您应该能够使用当前的INSERTS:

INSERT INTO AutoKeyEntity (Name,Description,EntityKey) VALUES
('AutoKey 254e3c64-485e-42a4-b1cf-d2e1e629df6a','Testing 5/4/2011 8:59:43 AM',DEFAULT)
returning EntityKey;
INSERT INTO AutoKeyEntityListed (EntityKey,Listed,ItemIndex) VALUES
(CURRVAL('autokeyentity_entityKey_seq'),'Test 1 AutoKey 254e3c64-485e-42a4-b1cf-d2e1e629df6a', 0),
(CURRVAL('autokeyentity_entityKey_seq'),'Test 2 AutoKey 254e3c64-485e-42a4-b1cf-d2e1e629df6a', 1),
(CURRVAL('autokeyentity_entityKey_seq'),'Test 3 AutoKey 254e3c64-485e-42a4-b1cf-d2e1e629df6a', 2);
-- etc.
Run Code Online (Sandbox Code Playgroud)

EntityKey从INSERT上一次抓取一个值AutoEntityKey.可能需要某种脚本来处理RETURNING值.您还可以在函数中包装AutoKeyEntity和相关的AutoKeyEntityListedINSERT,然后使用INTO获取EntityKey值并从函数返回它:

INSERT INTO AutoKeyEntity /*...*/ RETURNING EntityKey INTO ek;
/* AutoKeyEntityListed INSERTs ... */
RETURN ek;
Run Code Online (Sandbox Code Playgroud)

  • 这里非常重要的是返回值的顺序[不保证](https://www.postgresql.org/message-id/CAL9jXCHVg0CVEke%2BeiMjYA_UBffnacGYEN9Psb1h-kFw8QLxrw%40mail.gmail.com)与in中的相同查询 (2认同)

Den*_*rdy 5

您可以使用以下方法预先分配连续的 id:

SELECT setval(seq, nextval(seq) + num_rows - 1, true) as stop
Run Code Online (Sandbox Code Playgroud)

它应该是调用nextval()无数次的更快替代方法。

您还可以将 id 存储在临时表中:

create temporary blah (
  id int
) on commit drop;

insert into table1 (...) values (...)
returning id into blah;
Run Code Online (Sandbox Code Playgroud)

在 postgres 9.1 中,可以使用 CTE:

with
ids as (
insert into table1 (...) values (...)
    returning id
)
insert into table2 (...)
select ...
from ids;
Run Code Online (Sandbox Code Playgroud)