SQL 查询行迁移到它们的关系的不同出现

SQL query for rows migration to distinct occurences of their relations

我有以下包含示例数据的数据结构:

群组Table

id (PK) name foreign_id
A DUPLICATED_NAME X
B DUPLICATED_NAME X
C string Y
D string Z

项目Table(与群组相关)

id (PK) group_id
uuid value1 A
uuid value2 B
uuid value3 C
uuid value4 D

我的目标是摆脱 Groups 中的 id 列并创建 nameforeign_id 列新复合主键。

为此,我需要将现有的 迁移到不同的 。 例如,我发布的意思是,我需要删除 id = B 组,因为 DUPLICATED_NAMEgroup A,然后将所有 items 重新分配给 group_id = BA,因为 B 不再存在,依此类推,对于所有行.

我正在使用 PostgresSQL 和 Liquibase。

step-by-step demo:db<>fiddle

UPDATE items i
SET group_id = s.first_value  -- 3
FROM (
    SELECT
        i.*,
        g.first_value
    FROM items i
    JOIN (
        SELECT
            *,
            -- 1
            first_value(id) OVER (PARTITION BY name, foreign_key ORDER BY id)
        FROM groups
    ) g ON g.id = i.group_id  -- 2
) s
WHERE i.id = s.id;
  1. 使用 first_value() window function 查找重复组的第一个 id 值,该值作为唯一值添加到组的所有记录(=分区)
  2. 由老group_id
  3. 加入grouptable上itemstable
  4. 使用 first_value
  5. 更新 items table

如果要在同一个查询中为 groups table 执行 DELETE 语句,可以使用 CTEs (WITH clauses)

demo:db<>fiddle

WITH new_group_id AS (
    SELECT                                  -- 1
        i.*,
        g.id as g_id,
        g.first_value
    FROM items i
    JOIN (
        SELECT
            *,
            first_value(id) OVER (PARTITION BY name, foreign_key ORDER BY id)
        FROM groups
   ) g ON g.id = i.group_id
), update_items AS (
   UPDATE items i                           -- 2
   SET group_id = s.first_value
   FROM (SELECT * FROM new_group_id) s
   WHERE s.id = i.id
)
DELETE FROM groups                          -- 3
WHERE id IN (
    SELECT g_id
    FROM new_group_id
    WHERE g_id <> first_value
);
  1. 首先像上面那样计算新的group_id。将结果存储在 CTE 中,因为我们稍后会重复使用它两次。
  2. 像上面那样做UPDATE语句。唯一不同的是,我们没有使用子查询,而是使用之前计算的 CTE 结果
  3. 更新后我们可以再次使用查询来查找应该删除的记录(每条first_value与实际组的id不相同的记录)。执行DELETE语句。