INSERT INTO ... FROM SELECT ... RETURNING id 映射
INSERT INTO ... FROM SELECT ... RETURNING id mappings
我正在使用 PostgreSQL 9.3.
我想复制一些数据库记录。由于我为 table 使用自动递增 pk id,我想取回从重复记录生成的 id 到原始记录的 id 映射。例如,假设我有一个 table posts
其中有 2 条记录:
[{'id': 1, 'title': 'first'}
, {'id': 2. 'title': 'second'}]
与SQL:
INSERT INTO posts (title) SELECT title FROM posts RETURNING id, ??
我希望看到如下映射:
[{'id': 3, 'from_id': 1}
, {'id': 4, 'from_id': 2}]
知道如何填写上面的问号使其生效吗?非常感谢!
这对于 UPDATE
来说会更简单,其中加入更新的其他行对 RETURNING
子句可见:
- Return pre-UPDATE column values using SQL only
目前 对 INSERT
不可能。 The manual:
The expression can use any column names of the table named by table_name
table_name 是 INSERT
命令的目标。
您可以使用 (data-modifying) CTEs 使其正常工作。
假设 title
每个查询 唯一 ,否则你需要做更多:
WITH sel AS (
SELECT id, title
FROM posts
WHERE id IN (1,2) -- select rows to copy
)
, ins AS (
INSERT INTO posts (title)
SELECT title FROM sel
RETURNING id, title
)
SELECT ins.id, sel.id AS from_id
FROM ins
JOIN sel USING (title);
如果 title
不是每个查询唯一的(但至少 id
每个 table 是唯一的):
WITH sel AS (
SELECT id, title, row_number() OVER (ORDER BY id) AS rn
FROM posts
WHERE id IN (1,2) -- select rows to copy
ORDER BY id
)
, ins AS (
INSERT INTO posts (title)
SELECT title FROM sel ORDER BY id -- ORDER redundant to be sure
RETURNING id
)
SELECT i.id, s.id AS from_id
FROM (SELECT id, row_number() OVER (ORDER BY id) AS rn FROM ins) i
JOIN sel s USING (rn);
第二个查询依赖于未记录的实现细节,即按提供的顺序插入行。它适用于所有当前版本的 Postgres,并且可能不会崩溃。
恕我直言,最简单的解决方案是在 table 中添加一列,您可以在其中放置已克隆行的 ID。
如果 posts
的 id
列是 serial
类型,它的生成方式类似于 nextval('posts_id_seq'::regclass)
,
您可以为每个新行手动调用此函数
with
sel as (
SELECT id, title, nextval('posts_id_seq'::regclass) new_id
FROM posts
WHERE id IN (1,2)
),
ins as (
INSERT INTO posts (id, title)
SELECT new_id, title
FROM sel
)
SELECT id, new_id
FROM sel
它适用于任何数据,包括非唯一数据title
我正在使用 PostgreSQL 9.3.
我想复制一些数据库记录。由于我为 table 使用自动递增 pk id,我想取回从重复记录生成的 id 到原始记录的 id 映射。例如,假设我有一个 table posts
其中有 2 条记录:
[{'id': 1, 'title': 'first'}
, {'id': 2. 'title': 'second'}]
与SQL:
INSERT INTO posts (title) SELECT title FROM posts RETURNING id, ??
我希望看到如下映射:
[{'id': 3, 'from_id': 1}
, {'id': 4, 'from_id': 2}]
知道如何填写上面的问号使其生效吗?非常感谢!
这对于 UPDATE
来说会更简单,其中加入更新的其他行对 RETURNING
子句可见:
- Return pre-UPDATE column values using SQL only
目前 对 INSERT
不可能。 The manual:
The expression can use any column names of the table named by table_name
table_name 是 INSERT
命令的目标。
您可以使用 (data-modifying) CTEs 使其正常工作。
假设 title
每个查询 唯一 ,否则你需要做更多:
WITH sel AS (
SELECT id, title
FROM posts
WHERE id IN (1,2) -- select rows to copy
)
, ins AS (
INSERT INTO posts (title)
SELECT title FROM sel
RETURNING id, title
)
SELECT ins.id, sel.id AS from_id
FROM ins
JOIN sel USING (title);
如果 title
不是每个查询唯一的(但至少 id
每个 table 是唯一的):
WITH sel AS (
SELECT id, title, row_number() OVER (ORDER BY id) AS rn
FROM posts
WHERE id IN (1,2) -- select rows to copy
ORDER BY id
)
, ins AS (
INSERT INTO posts (title)
SELECT title FROM sel ORDER BY id -- ORDER redundant to be sure
RETURNING id
)
SELECT i.id, s.id AS from_id
FROM (SELECT id, row_number() OVER (ORDER BY id) AS rn FROM ins) i
JOIN sel s USING (rn);
第二个查询依赖于未记录的实现细节,即按提供的顺序插入行。它适用于所有当前版本的 Postgres,并且可能不会崩溃。
恕我直言,最简单的解决方案是在 table 中添加一列,您可以在其中放置已克隆行的 ID。
如果 posts
的 id
列是 serial
类型,它的生成方式类似于 nextval('posts_id_seq'::regclass)
,
您可以为每个新行手动调用此函数
with
sel as (
SELECT id, title, nextval('posts_id_seq'::regclass) new_id
FROM posts
WHERE id IN (1,2)
),
ins as (
INSERT INTO posts (id, title)
SELECT new_id, title
FROM sel
)
SELECT id, new_id
FROM sel
它适用于任何数据,包括非唯一数据title