具有意外相似重复的 postgres 用户表导致另一个表具有混乱的外键,如何修复和合并外键?

Posted

技术标签:

【中文标题】具有意外相似重复的 postgres 用户表导致另一个表具有混乱的外键,如何修复和合并外键?【英文标题】:A postgres users table with unintended similar-duplicates has led to another table with messy foreign-keys, how to fix and consolidate foreign-keys? 【发布时间】:2020-01-30 17:53:16 【问题描述】:

对于我的应用程序,使用 Postgres...

问题

每个用户应该关联N个case,定义一对多的关系,但由于应用逻辑错误,用户在DB中普遍存在重复,导致多个id对于任何给定的人。

鉴于大多数用户的这些类型的近似重复,这导致每个用户几乎总是由 users 表中的 Y 个 ID 表示。

在这种情况下,近似重复意味着两行大部分相似。这是一个几乎重复的例子。

|  id | first_name | last_name | str_adrr      | 
------------------------------------------------
|  1  | Mary       | Doe       | 124 Main Ave  | 
|  2  | Mary       | Doe       | 124 Main St   |

目标是删除所有几乎重复的用户,除了一个用户,留下一个用户,同时将所有相关案例与该单个用户相关联。最终在用户和案例之间建立一对多的关系。

我的方法

第一步

我对用户进行模糊匹配,并按 cluster_id 作为标识符对其进行分组。其中cluster_id用于表示分组本身;所有带有 cluster_id 1 的行都被认为是重复的。

这是users 表的示例

|  id | first_name | last_name | str_adrr      | group                   | cluster_id
-------------------------------------------------------------------------------------
|  1  | Mary       | Doe       | 124 Main Ave  | Mary Doe 124 Main Ave   | 1
|  2  | Mary       | Doe       | 124 Main St   | Mary Doe 124 Main Ave   | 1
|  7  | Mary       | Doe       | 124 Main Ave  | Mary Doe 124 Main Ave   | 1
|  4  | Mary       | Does      | 124 Main Ave  | Mary Doe 124 Main Ave   | 1
|  5  | James      | Smith     | 14 Street NW  |James Smith 14 Street NW | 2
|  6  | James      | Smith     | 14 Street NW  |James Smith 14 Street NW | 2
| 10  | James      | Smth      | 14 Street NW  |James Smith 14 Street NW | 2
| 11  | Paula      | James     | 21 River SW   | Paula James21 River SW  | 3
| 45  | Paula      | James     | 21 River SW   | Paula James21 River SW  | 3

给定另一个名为cases 的表。以下是该表中相关列的示例:

|  id | user_id
---------------
|  1  | 1  # corresponds to mary
|  2  | 2  # corresponds to mary
|  3  | 4  # corresponds to mary
|  4  | 7  # corresponds to mary
|  5  | 10 # corresponds to james
|  6  | 11 # corresponds to paula
|  7  | 45 # corresponds to paula
|  8  | 1  # corresponds to mary
|  9  | 10 # corresponds to james
|  10 | 10 # corresponds to james
|  11 | 6  # corresponds to james

cases 表中的user_id 对应于users 表中的id

一个 user_id 可以有很多(最多几千个)案例。

第二步

我加入了userscases

这是结果表的示例,users_cases

|cluster_id| user_id| case_id
----------------------------------
|  1       | 1      | 1
|  1       | 1      | 8
|  1       | 2      | 2
|  1       | 4      | 3
|  1       | 7      | 4
|  2       | 10     | 5
|  2       | 10     | 9
|  2       | 10     | 10
|  2       | 6      | 11
|  3       | 11     | 6
|  3       | 11     | 7

第三步

我需要确定给定cluster_id 分组中的哪个user_iduser_cases 表中最多的案例相关联。

我能够这样做并最终得到一个具有以下形状的max_cluster_user

|cluster_id| user_id| case_id_count
-------------------------------------
| 1        | 1      | 2 
| 2        | 10     | 3 
| 3        | 11     | 1 

翻译。第一行表示cluster_id的值为1,其中user_id的事例数最多的是2,事例数量由case_id_count表示,其值为2

第 4 步:我需要帮助的地方

然后我需要更新user_cases 表(或创建一个具有相同形状的新表),以便每个user_id 对于cluster_id 组中的每一行都是相同的。结果应该是这样的

|cluster_id| user_id| case_id
----------------------------------
|  1       | 1      | 1
|  1       | 1      | 8
|  1       | 1      | 2
|  1       | 1      | 3
|  1       | 1      | 4
|  2       | 10     | 5
|  2       | 10     | 9
|  2       | 10     | 10
|  2       | 10     | 11
|  3       | 11     | 6
|  3       | 11     | 7

我不知道如何做到这一点。约束是它必须通过与 Postgresql 兼容的 SQL 来完成。

步骤 4 的程序代码解决方案

我确实将其草拟为代码,以便在程序上考虑它,这可能会有所帮助。虽然我知道这不是一个可行的解决方案,因为有超过 500k 条记录,但这种类型的逻辑需要数天才能按原样运行。

# max_cluster_user refers to the table of the same name
for cluster in max_cluster_user: 
    # get the users within a specific cluster
    cluster_users = [user for user in users if user['cluster_id'] == cluster['cluster_id']]
    # users refers to the table of the same name
    for user in cluster_users:
        # get the cases associated with the given id
        user_cases = [case for case in cases if case['user_id'] == user['id']
        for user_case in user_cases:
            # update the user_id for a case
            user_case['user_id = cluster['user_id']

提前致谢

【问题讨论】:

【参考方案1】:

我认为您只需要 update 加入第 4 步即可:

update user_cases uc
    set user_id = mcu.user_id
    from max_cluster_user mcu
    where mcu.cluster_id = uc.cluster_id and
          uc.user_id <> mcu.user_id;

【讨论】:

我会接受你的回答。我刚刚测试,它的工作原理!谢谢

以上是关于具有意外相似重复的 postgres 用户表导致另一个表具有混乱的外键,如何修复和合并外键?的主要内容,如果未能解决你的问题,请参考以下文章

将两个具有相似列值的数据框合并在一起[重复]

无法创建唯一索引,键重复 django postgres

使用 Activerecord、Rails 和 Postgres 查找具有多个重复字段的行

如何解决由于强制展开导致的致命意外零错误[重复]

加入具有另一个表的两个公共列的 postgres 表

节点 postgres 并获得具有重复名称的连接字段