Таблица пользователей postgres с непреднамеренными аналогичными дубликатами привела к другой таблице с грязными внешними ключами, как исправить и объединить внешние ключи? - PullRequest
2 голосов
/ 30 января 2020

Для моего приложения, используя Postgres ...

Проблема

Каждый пользователь должен быть связан с N-числом случаев, определяя одно- отношение ко многим, но из-за неправильной логики приложения c пользователи обычно дублируются в БД, что приводит к нескольким идентификаторам для каждого конкретного человека.

Учитывая, что эти типы почти дублируют большинство пользователей, это привело к тому, что каждый пользователь будет почти всегда представлен Y-числом идентификаторов в таблице users.

В этом контексте почти дубликат означает две строки, которые в основном похожи. Вот пример почти дубликата.

|  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

user_id в этой таблице cases соответствует id из таблицы users

Пользовательский идентификатор может есть много (до нескольких тысяч) дел.

Шаг 2

Я присоединился к таблицам users и cases

Вот пример таблицы результатов , 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

Шаг 3

Мне нужно было определить, какой user_id в данной группе cluster_id связан с наибольшим количеством случаев из user_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

Я набросал это как код, чтобы обдумать это процедурно, это может помочь. Хотя я знаю, что это не жизнеспособное решение, так как при> 500 тыс. Записей для этого типа логи c потребуется несколько дней, чтобы работать как есть.

# 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 Ответ

1 голос
/ 30 января 2020

Я думаю, вам просто нужно 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...