从 Posgtres 批量插入返回多个 SERIAL 值
我正在使用 Postgres,使用 SERIAL
作为我的主键。插入一行后,我可以使用“RETURNING
”或CURRVAL()
获取生成的密钥。
现在我的问题是我想在事务中进行批量插入并获取所有生成的密钥。
我使用 RETURNING
和 CURRVAL
得到的只是最后生成的 id,其余结果将被丢弃。
我怎样才能让它返回所有这些?
谢谢
Im working with Postgres, using SERIAL
as my primary key. After I insert a row I can get the generated key either by using 'RETURNING
' or CURRVAL()
.
Now my problem is that I want to do a batch insert inside a transaction and get ALL the generated keys.
All I get with RETURNING
and CURRVAL
is the last generated id, the rest of the result get discarded.
How can I get it to return all of them?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您可以将
RETURNING
与多个值一起使用:因此您想要更像这样的内容:
然后您必须从事务中的每个语句收集返回的
EntityKey
值。您可以尝试在事务开始和结束时获取序列的当前值,并使用它们来确定使用了哪些序列值,但是 这不可靠:
因此,即使您的序列的缓存值为 1,您的事务中仍然可以具有非连续的序列值。但是,如果序列的缓存值与事务中的插入数量匹配,您可能是安全的,但我猜这会太大而没有意义。
更新:我刚刚注意到(感谢提问者的评论)涉及到两个表格,在文字墙中有点迷失了。
在这种情况下,您应该能够使用当前的插入:
并从
AutoEntityKey
上的插入中一次获取一个EntityKey
值。可能需要某种脚本来处理返回值。您还可以将 AutoKeyEntity 和相关的 AutoKeyEntityListed INSERT 包装在函数中,然后使用INTO
获取EntityKey
值并从函数返回它:You can use
RETURNING
with multiple values:So you want something more like this:
And then you'll have to gather the returned
EntityKey
values from each statement in your transaction.You could try to grab the sequence's current value at the beginning and end of the transaction and use those to figure out which sequence values were used but that is not reliable:
So, even if your sequences have cache values of one you can still have non-contiguous sequence values in your transaction. However, you might be safe if the sequence's cache value matches the number of INSERTs in your transaction but I'd guess that that's going to be too large to make sense.
UPDATE: I just noticed (thanks to the questioner's comments) that there are two tables involved, got a bit lost in the wall of text.
In that case, you should be able to use the current INSERTS:
And grab the
EntityKey
values one at a time from the INSERTs onAutoEntityKey
. Some sort of script might be needed to handle the RETURNING values. You could also wrap theAutoKeyEntity
and relatedAutoKeyEntityListed
INSERTs in a function, then useINTO
to grab theEntityKey
value and return it from the function:您可以使用此方法预先分配连续的 id:
它应该是调用
nextval()
无数次的更快替代方案。您还可以将 ids 存储在临时表中:
在 postgres 9.1 中,可以使用 CTE:
you can pre-assign consecutive ids using this:
it should be a faster alternative to calling
nextval()
gazillions of times.you could also store ids in a temporary table:
in postgres 9.1, can able to use CTEs:
在您的应用程序中,从序列中收集值:
使用这些值创建行,然后简单地插入(使用多行插入)。它是安全的(SERIAL 按照您的预期工作,不重用值、并发证明等)并且快速(您一次插入所有行,无需多次客户端-服务器往返)。
In your application, gather values from the sequence :
Create your rows using those values, and simply insert (using a multiline insert). It's safe (SERIAL works as you'd expect, no reuse of values, concurrent proof, etc) and fast (you insert all the rows at once without many client-server roundtrips).
更详细地回复 Scott Marlowe 的评论:
假设您有一个树表,其中通常的parent_id 引用自身,并且您想要导入一个大的记录树。问题是您需要知道父级的 PK 值才能插入子级,因此可能需要大量单独的 INSERT 语句。
因此,解决方案可能是:
Replying to Scott Marlowe's comment in more detail :
Say you have a tree table with the usual parent_id reference to itself, and you want to import a large tree of records. Problem is you need the parent's PK value to be known to insert the children, so potentially this can need lots of individual INSERT statements.
So a solution could be :
有三种方法可以做到这一点。使用 currval()、使用返回或编写一个存储过程将这些方法中的任何一个包装在一个漂亮的小毯子中,这样您就不必在半客户端半 postgres 中完成这一切。
There are three ways to do this. Use currval(), use returning, or write a stored procdure to wrap either of those methods in a nice little blanket that keeps you from doing it all in half client half postgres.
执行FOR循环并逐条处理记录。它的性能可能较差,但它是并发安全的。
示例代码:
Perform a FOR LOOP and process records one by one. It might be less performant but it is concurrency safe.
Example code: