假设文本是唯一的,您可以这样做:
demo:db<>fiddle
WITH ins AS (
INSERT INTO tablea(type, related_id, another1)
SELECT 3, null, another1
FROM tablea
WHERE type = 1
RETURNING id, another1
)
UPDATE tablea t
SET related_id = s.id
FROM (
SELECT * FROM ins
) s
WHERE s.another1 = t.another1 AND t.type = 1
WITH 子句允许顺序执行两个单独的语句。所以首先插入新数据。使用新生成的 ID,您可以在之后更新旧数据。因为你必须匹配原始数据,所以文本作为标识符很有帮助。
这仅在您不必使用 (1, 'something') 的数据集时才有效。那么就很难确定这两个记录中的哪一个是每个副本的原始记录。
另一种方法是将 type1-ids 也存储在新的 type3-columns 中。如果这对你来说没问题,你可以这样做:
demo:db<>fiddle
WITH ins AS (
INSERT INTO tablea(type, related_id, another1)
SELECT 3, id, another1
FROM tablea
WHERE type = 1
RETURNING id, related_id, another1
)
UPDATE tablea t
SET related_id = s.id
FROM (
SELECT * FROM ins
) s
WHERE s.related_id = t.id
这会将原始的 type1-ids 存储在新的相关 ID 列中。因此,在每种情况下,都可以通过该值找到原始 id。
不幸的是,您不能在另一个 WITH 子句中将这些列设为 NULL,因为 WITH 子句仅适用于现有数据。此时查询本身尚未完成。所以新记录在物理上并不存在。
这个可以用……
demo:db<>fiddle
WITH to_be_copied AS (
SELECT id, another1
FROM tablea
WHERE type = 1
), ins AS (
INSERT INTO tablea(type, related_id, another1)
SELECT 3, null, another1
FROM to_be_copied
ORDER BY id -- 1
RETURNING id, another1
)
UPDATE tablea t
SET related_id = s.type3_id
FROM (
SELECT
*
FROM
(SELECT id as type1_id, row_number() OVER (ORDER BY id) FROM to_be_copied) tbc
JOIN
(SELECT id as type3_id, row_number() OVER (ORDER BY id) FROM ins) i
ON tbc.row_number = i.row_number
) s
WHERE t.id = s.type1_id
此解决方案假定 (1) 处的给定顺序确保新记录的插入顺序。事实上,我不太确定。但如果是这样:首先查询所有 type1 记录。之后有复制(以相同的顺序!)。之后,旧的和新的记录 id 被取走。 row_number() 窗口函数将连续的行数添加到记录中。因此,如果两个数据集具有相同的顺序,则旧 id 应该获得与其对应的新 id 相同的行号。在这种情况下,识别是可能的。对于这个工作的小例子......
--> 编辑:这似乎是在说:是的,从 Postgres 9.6 开始,订单将被保留https://stackoverflow.com/a/50822258/3984221