Sql 是否为每个选定行插入另一行?

Sql 是否为每个选定行插入另一行?,sql,postgresql,Sql,Postgresql,我有一张单人桌。它有id、type、relatedId、其他1、其他2列。列type可以有值1、2或3。 我需要的是,对于TableA中的每一行,其中type=1,在同一个表中插入另一行,并使用新插入行的id更新原始行(列relatedId)。此外,新插入行中某些列的值应复制自原始列 因此,对于当前状态: id|type|relatedId|another1 10| 1 |null|"some text" 11| 2 |null|"somthing" 12| 1 |null|"somth

我有一张单人桌。它有
id
type
relatedId
其他1
其他2
列。列
type
可以有值
1、2或3
。 我需要的是,对于TableA中的每一行,其中
type=1
,在同一个表中插入另一行,并使用新插入行的
id
更新原始行(列
relatedId
)。此外,新插入行中某些列的值应复制自原始列

因此,对于当前状态:

id|type|relatedId|another1

10| 1  |null|"some text"
11| 2  |null|"somthing"
12| 1  |null|"somthing else"
结果如下:

id|type|relatedId|another1

10| 1  |13  |"some text"      - now has relationship to 13
11| 2  |null|"somthing"
12| 1  |14  |"somthing else"  - now has relationship to 13
13| 3  |null|"some text"      - inserted, "another1" is copied from 10
14| 3  |null|"somthing else"  - inserted, "another1" is copied from 12

假设文本是唯一的,您可以这样做:

WITH子句允许按顺序执行两个单独的语句。因此,首先插入新数据。使用新生成的ID,您可以在以后更新旧数据。因为您必须匹配原始数据,所以文本作为标识符很有用

这仅在不必使用(1,'something')创建数据集的情况下有效。那么就很难确定哪两份记录是每份副本的原件


另一种方法是在新的type3列中存储type1 ID。如果这对您合适,您可以这样做:

这会将原始的type1 id存储在新id的“相关id”列中。因此,在任何情况下,都可以在该值上找到原始id

不幸的是,您不能在另一个WITH子句中清空这些列,因为WITH子句只处理现有数据。目前查询本身还没有完成。因此,新记录在物理上并不存在


这个可以用

此解决方案假定(1)处的给定顺序确保了新记录的插入顺序。事实上,我不是很确定。但如果是这样的话:首先查询所有的type1记录。之后,将复制(按相同的顺序!)。之后,将获取旧记录ID和新记录ID。row_number()窗口函数将连续的行计数添加到记录中。因此,如果两个数据集具有相同的顺序,则旧ID应获得与其对应的新ID相同的行号。在这种情况下,可以进行识别。对于一个小例子,这是有效的


-->编辑:这似乎表明:是的,自Postgres 9.6以来,顺序将保留

假设文本是唯一的,您可以这样做:

WITH子句允许按顺序执行两个单独的语句。因此,首先插入新数据。使用新生成的ID,您可以在以后更新旧数据。因为您必须匹配原始数据,所以文本作为标识符很有用

这仅在不必使用(1,'something')创建数据集的情况下有效。那么就很难确定哪两份记录是每份副本的原件


另一种方法是在新的type3列中存储type1 ID。如果这对您合适,您可以这样做:

这会将原始的type1 id存储在新id的“相关id”列中。因此,在任何情况下,都可以在该值上找到原始id

不幸的是,您不能在另一个WITH子句中清空这些列,因为WITH子句只处理现有数据。目前查询本身还没有完成。因此,新记录在物理上并不存在


这个可以用

此解决方案假定(1)处的给定顺序确保了新记录的插入顺序。事实上,我不是很确定。但如果是这样的话:首先查询所有的type1记录。之后,将复制(按相同的顺序!)。之后,将获取旧记录ID和新记录ID。row_number()窗口函数将连续的行计数添加到记录中。因此,如果两个数据集具有相同的顺序,则旧ID应获得与其对应的新ID相同的行号。在这种情况下,可以进行识别。对于一个小例子,这是有效的

-->编辑:这似乎表明:是的,顺序将被保留,因为Postgres 9.6

根据,Postgres保留了从9.6起通过
选择
插入的行的顺序,并使用显式
排序依据
。我们可以使用它将插入的行与它们使用
row\u number()
生成的行连接起来

在第一个CTE中,我们得到所有的行,这些行应该与它们的
row_number()
一起按ID排序插入。在第二个CTE中,我们通过从第一个CTE中选择来插入它们,并按ID显式排序。我们在第二个CTE中返回插入的ID,以便我们可以在第三个CTE中选择它,在第三个CTE中再次添加
row_number()
按ID排序。我们现在可以通过行号加入第一个和第三个CTE,以获得原始ID和新插入的ID对。在此基础上,我们可以更新设置相关ID的表

根据Postgres,从9.6起,保留通过
选择
插入的行的顺序,并使用显式
顺序BY
。我们可以使用它将插入的行与它们使用
row\u number()
生成的行连接起来

在第一个CTE中,我们得到所有的行,这些行应该与它们的
row_number()
一起按ID排序插入。在第二个CTE中,我们通过从第一个CTE中选择来插入它们,并按ID显式排序。我们在第二个CTE中返回插入的ID,以便我们可以在第三个CTE中选择它,在第三个CTE中再次添加
row_number()
按ID排序。我们现在可以通过行号加入第一个和第三个CTE,以获得原始ID和新插入的ID对。在此基础上,我们可以更新设置相关ID的表


添加了另一个query@testuser这有用吗?请不要忘记接受正确的答案,否则请告诉我们要更改什么query@testuser这有用吗?请不要忘记接受正确的答案,否则告诉我们要更改什么有趣的是:代码略有不同,但绝对相同
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 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
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
WITH
"cte1"
AS
(
SELECT "id",
       3 "type",
       "related_id",
       "another1",
       row_number() OVER (ORDER BY "id") "rn"
       FROM "tablea"
       WHERE "type" = 1
),
"cte2"
AS
(
INSERT INTO "tablea"
            ("type",
             "another1")
       SELECT "type",
              "another1"
              FROM "cte1"
              ORDER BY "id"
       RETURNING "id"
),
"cte3"
AS
(
SELECT "id",
       row_number() OVER (ORDER BY "id") "rn"
       FROM "cte2"
)
UPDATE "tablea"
       SET "related_id" = "cte3"."id"
       FROM "cte1"
            INNER JOIN "cte3"
                       ON "cte3"."rn" = "cte1"."rn"
       WHERE "cte1"."id" = "tablea"."id";