我正在使用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)
您可以使用以下方法预先分配连续的 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)
| 归档时间: |
|
| 查看次数: |
10140 次 |
| 最近记录: |