PostgreSQL:调整孩子的外键以消除父母的重复

时间:2018-09-28 22:28:49

标签: postgresql

我已经接管了一个项目,该项目在PostgreSQL中有一些现有数据需要调整。具体来说,在团队属于联赛的系统中,我需要从联赛表中删除重复的名称。为此,我需要在teams表中调整外键,以使它们不再引用将要删除的联赛。请注意,我删除哪个联赛和保留哪个联赛都没有关系,只要我为每个不同的联赛名称保留一个联赛即可。

通过示例更容易解释。在下面,我们可以看到“红松鼠”和“绿猴”都属于“西部联盟”联盟,尽管目前有两行名为“西部联盟”。我需要删除Leagues表中的行,以使联盟名称唯一,但是首先我需要更改teams表中的league_ids,以便他们引用不会删除的League行。

  leagues
  id  | name
  1   | "Western League"
  2   | "Western League"
  3   | "Eastern League"

  teams
  id  | league_id | name
  1   | 1         | "Red Squirrels"
  2   | 2         | "Green Monkeys"
  3   | 3         | "Blue Ducks"

在上面的简单示例中,目标是将“绿猴”上的League_id更改为1,以便“红松鼠”和“绿猴”都引用同一个联赛。此后,没有团队引用第二个“西部联盟”联赛,可以将其删除。我们的数据太多,无法逐行进行更改。

真的很感谢您的帮助。谢谢!

1 个答案:

答案 0 :(得分:1)

此查询显示应将哪个联赛替换为另一个联赛:

select id, min(id) over (partition by name) as correct_id
from leagues

 id | correct_id 
----+------------
  3 |          3    -- ok
  1 |          1    -- ok
  2 |          1    -- needs replacing
(3 rows)

如果我们与团队一起加入,我们可以选择需要更正的团队:

select t.id as team_id, correct_id
from (
    select id, min(id) over (partition by name) as correct_id
    from leagues
    ) l
join teams t on t.league_id = l.id
where t.league_id <> correct_id

 team_id | correct_id 
---------+------------
       2 |          1
(1 row)

使用最后一个查询来更新团队:

update teams
set league_id = correct_id
from (
    select t.id as team_id, correct_id
    from (
        select id, min(id) over (partition by name) as correct_id
        from leagues
        ) l
    join teams t on t.league_id = l.id
    where t.league_id <> correct_id
    ) c
where id = team_id
returning team_id, name, correct_id

 team_id |      name       | correct_id 
---------+-----------------+------------
       2 | "Green Monkeys" |          1
(1 row)