PostgreSQL:从 COPY FROM 插入返回自动生成的 ID

问题描述

我有一个带有 GENERATED ALWAYS AS IDENTITYid 的非空 Postgresql 表。我使用 C++ 绑定 pqxx::stream_to 进行批量插入,我假设它使用 copY FROM。我的问题是我想知道新创建的行的 id,但 copY FROM 没有 RETURNING 子句。我看到了几种可能的解决方案,但我不确定它们中是否有任何一个是好的,或者哪个最不坏:

  • 通过 id 手动提供 copY FROM,注意提供身份序列将提供的值,然后将序列与 setval(...) 同步。>

  • 首先将数据流式传输到带有自定义索引列的临时表以进行排序。然后做类似

    INSERT INTO foo (col1,col2)
    SELECT ttFoo.col1,ttFoo.col2 FROM ttFoo
    ORDER BY ttFoo.idx RETURNING foo.id
    并取决于身份序列产生升序数字以将它们与 ttFoo.idx 相关联的事实(我也不能做 RETURNING ttFoo.idx,因为只有插入的行可用于不包含 idx 的行)

  • 在插入前查询身份序列的当前值,然后检查哪些行是新的。

我认为这是一种常见情况,但我没有看到明显正确的解决方案。你有什么推荐?

解决方法

您可以使用 system columns 找出哪些行受到当前事务的影响。 xmin 列包含插入事务的 ID,因此要返回您刚刚复制的 id 值,您可以:

BEGIN;

COPY foo(col1,col2) FROM STDIN;

SELECT id FROM foo
WHERE xmin::text = (txid_current() % (2^32)::bigint)::text
ORDER BY id;

COMMIT;

WHERE 子句来自 this answer,它解释了其背后的推理。

我认为没有任何方法可以使用索引对其进行优化,因此在大表上可能会太慢。如果是这样,我认为你的第二个选择是要走的路,即流入临时表和 INSERT ... RETURNING