高效地复制 PostgreSQL 表中的某些行
我有 PostgreSQL 9 数据库,它使用自动递增整数作为主键。我想复制表中的某些行(基于某些过滤条件),同时更改一个或两个值,即复制所有列值,但 ID(自动生成)和可能的另一列除外。
但是,我还想获取从旧 ID 到新 ID 的映射。有没有更好的方法来做到这一点,然后只查询要复制的行,然后一次插入一个新行?
本质上我想做这样的事情:
INSERT INTO my_table (col1, col2, col3)
SELECT col1, 'new col2 value', col3
FROM my_table old
WHERE old.some_criteria = 'something'
RETURNING old.id, id;
但是,这失败了,错误:缺少表“旧”的 FROM 子句条目,我可以明白为什么:Postgres 必须首先执行 SELECT,然后插入它并且 RETURNING
子句只能访问新插入的行。
I have PostgreSQL 9 database that uses auto-incrementing integers as primary keys. I want to duplicate some of the rows in a table (based on some filter criteria), while changing one or two values, i.e. copy all column values, except for the ID (which is auto-generated) and possibly another column.
However, I also want to get the mapping from old to new IDs. Is there a better way to do it then just querying for the rows to copy first and then inserting new rows one at a time?
Essentially I want to do something like this:
INSERT INTO my_table (col1, col2, col3)
SELECT col1, 'new col2 value', col3
FROM my_table old
WHERE old.some_criteria = 'something'
RETURNING old.id, id;
However, this fails with ERROR: missing FROM-clause entry for table "old"
and I can see why: Postgres must be doing the SELECT first and then inserting it and the RETURNING
clauses only has access to the newly inserted row.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
RETURNING 只能引用最后插入的行中的列。您不能以这种方式引用“旧”ID,除非表中有一列同时保存它和新 ID。
尝试运行它,它应该可以工作,并且会显示您可以通过 RETURNING 获得的所有可能值:
它不会为您提供您想要的行为,但应该更好地说明 RETURNING 的设计工作方式。
RETURNING can only refer to the columns in the final, inserted row. You cannot refer to the "OLD" id this way unless there is a column in the table to hold both it and the new id.
Try running this which should work and will show all the possible values that you can get via RETURNING:
It won't get you the behavior you want, but should illustrate better how RETURNING is designed to work.
这可以借助数据修改 CTE (Postgres 9.1+) 来完成:
SQL Fiddle 演示。
这依赖于未记录的实现细节:
SELECT
中的行按提供的顺序插入(并按提供的顺序返回)。它适用于所有当前版本的 Postgres,并且不会损坏。相关:RETURNING
子句,因此我在另一个子查询中应用row_number()
。稍后相关答案中有更多解释:
This can be done with the help of data-modifiying CTEs (Postgres 9.1+):
SQL Fiddle demonstration.
This relies on the undocumented implementation detail that rows from a
SELECT
are inserted in the order provided (and returned in the order provided). It works in all current versions of Postgres and is not going to break. Related:Window functions are not allowed in the
RETURNING
clause, so I applyrow_number()
in another subquery.More explanation in this related later answer:
好的!我测试了这段代码,但我改变了
(
FROM my_table
) 中的 (FROM my_table AS old
) 和(
WHERE old.some_criteria = 'something'
) in (WHERE some_criteria = 'something'
)这是我使用的最终代码
谢谢!
Good! I test this code, but I change
this (
FROM my_table AS old
) in (FROM my_table
) andthis (
WHERE old.some_criteria = 'something'
) in (WHERE some_criteria = 'something'
)This is the final code that I use
Thanks!
在插入之前添加另一个更新以修改另一个字段
add another update before the insert to modify another field
“old”是保留字,由规则重写系统使用。
[我认为这个查询片段不是规则的一部分;在这种情况下,你会以不同的方式表达这个问题]
'old' is a reserved word, used by the rule rewrite system.
[ I presume this query fragment is not part of a rule; in that case you would have phrased the question differently ]