MySQL дублирует, как указать, когда две записи на самом деле НЕ дублируются?

У меня интересная проблема, и моя логика не соответствует задаче.

У нас есть таблица, в которой иногда появляются повторяющиеся записи (по технологическим причинам, и это неизбежно). Возьмем следующий пример:

id  FirstName  LastName  PhoneNumber   email
--  ---------  --------  ------------  --------------
 1  John       Doe       123-555-1234  [email protected]
 2  Jane       Smith     123-555-1111  [email protected]
 3  John       Doe       123-555-4321  [email protected]
 4  Bob        Jones     123-555-5555  [email protected]
 5  John       Doe       123-555-0000  [email protected]
 6  Mike       Roberts   123-555-9999  [email protected]
 7  John       Doe       123-555-1717  [email protected]

Мы находим дубликаты таким образом:

SELECT c1.* 
FROM `clients` c1
INNER JOIN (
    SELECT `FirstName`, `LastName`, COUNT(*)
    FROM `clients`
    GROUP BY `FirstName`, `LastName`
    HAVING COUNT(*) > 1
) AS c2
ON c1.`FirstName` = c2.`FirstName`
AND c1.`LastName` = c2.`LastName`

Это генерирует следующий список дубликатов:

id  FirstName  LastName  PhoneNumber   email
--  ---------  --------  ------------  --------------
 1  John       Doe       123-555-1234  [email protected]
 3  John       Doe       123-555-4321  [email protected]
 5  John       Doe       123-555-0000  [email protected]
 7  John       Doe       123-555-1717  [email protected]

Как видите, на основе FirstName и LastName все записи дублируются.

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

После этого мы узнаем (например), что записи 1 и 3 — настоящие дубликаты, а записи 5 и 7 — на самом деле совершенно два разных человека.

Таким образом, мы объединяем любые внешне связанные данные из записей 1 и 3 в запись 1, удаляем запись 3 и оставляем записи 5 и 7 в покое.

Теперь возникает проблема:

В следующий раз, когда мы повторно запустим запрос «дубликаты», он будет содержать следующие строки:

id  FirstName  LastName  PhoneNumber   email
--  ---------  --------  ------------  --------------
 1  John       Doe       123-555-4321  [email protected]
 5  John       Doe       123-555-0000  [email protected]
 7  John       Doe       123-555-1717  [email protected]

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

Как бы вы определили, что эти записи не являются дубликатами?

Сначала я создал таблицу поиска, определяющую, какие записи не являются дубликатами друг друга (например, {1,5}, {1,7}, {5,7}), но я понятия не имею, как построить запрос, который сможет использовать эти данные.

Кроме того, если появится другая повторяющаяся запись, это может быть дубликат 1, 5 или 7, поэтому нам нужно, чтобы они все отображались в списке дубликатов, чтобы сотрудник службы поддержки мог позвонить человеку в новой записи, чтобы выяснить, какой записи он может быть дубликатом.

Я натянут до предела, пытаясь понять это. Есть ли блестящие гении, которые хотели бы попробовать это?


person pbarney    schedule 18.09.2010    source источник


Ответы (2)


Интересная проблема. Вот моя трещина в этом.

Как насчет того, чтобы подойти к проблеме с несколько иной точки зрения.

Учтите, что система чиста для начала, т.е. все записи в настоящее время в системе либо с уникальными комбинациями имени + фамилии, либо с теми же самыми именами и фамилиями, которые уже подтверждены вручную как разные люди.

В момент ввода НОВОГО пользователя в систему у нас проходит дополнительная проверка. Может быть реализован как триггер INSERT или просто другая процедура, вызываемая после успешного выполнения вставки.

  1. Этот триггер/процедура сопоставляет ПЕРВОЕ + ПОСЛЕДНЕЕ имя комбинации «Вставленная» запись со всеми существующими записями в таблице.
  2. Для всех совпадающих имен «Имя + Фамилия» будет создана запись в таблице соответствия (новая таблица) с NewUserID, ExistingMatchingRecordsUserID.

С точки зрения SQL,

TABLE MatchingTable
COLUMNS 1. NewUserID 2. ExistingUserID
Constraint : Logical PK = NewUserID + ExistingMatchingRecordsUserID

INSERT INTO MATCHINGTABLE VALUES ('NewUserId', userId)
SELECT userId FROM User  u where u.firstName = 'John' and u.LastName = 'Doe'

Все записи в MatchingTable нуждаются в разрешении.

Когда, скажем, администратор входит в систему, администратор видит список всех записей в MatchingTable.

например: Новый пользователь Джон Доу - (ID 345) - 3 Возможные совпадения Джон Доу - ID 123 ID 231 / ID 256

Администратор сверит данные для 345 с данными в 123 / 231 и 256 и вручную подтвердит, дублируется ли ЛЮБОЙ / Нет. Если дублируется, 345 удаляется из пользовательской таблицы (мягкое / жесткое удаление - что вам подходит). Если НЕ, записи для ID 354 просто удаляются из MatchingTable (здесь я бы выбрал жесткое удаление, так как это похоже на транзакционную временную таблицу, но опять же все в порядке).

Кроме того, когда записи с идентификатором 354 удаляются из MatchingTable, все другие записи в MatchingTable, где ExistingMatchingRecordsUserID = 354, автоматически удаляются, чтобы исключить необходимость ненужной ручной проверки уже проверенных данных.

Опять же, это может быть потенциальным триггером DELETE/простой логикой, выполняемой дополнительно при DELETE MatchingTable. Реализация зависит от предпочтений.

person Jagmag    schedule 18.09.2010
comment
Это решение отлично подошло для моих нужд. Честно говоря, я не думаю, что нашел бы свой путь к этому решению, если бы вы не изложили его так хорошо. Благодарю вас! - person pbarney; 30.09.2010

За счет добавления одного байта на строку в вашу таблицу вы можете добавить столбец manually_verified BOOL со значением по умолчанию FALSE. Установите его на TRUE, если вы вручную проверили данные. Затем вы можете просто запросить, где manually_verified = FALSE.

Это просто, эффективно и соответствует тому, что на самом деле происходит в бизнес-процессах: вы вручную проверяете данные.

Если вы хотите пойти дальше, вы можете сохранить, когда строка была проверена и кто ее проверил. Поскольку это может быть неудобно хранить в основной таблице, вы, безусловно, можете сохранить его в отдельной таблице и LEFT JOIN в данных проверки. Вы даже можете создать представление, чтобы воссоздать внешний вид одной главной таблицы.

Чтобы решить проблему добавления нового дубликата: вы должны сравнить непроверенные данные со всем набором данных. Это означает, что ваша основная таблица c1 будет иметь условие manually_verified = FALSE, а ваша INNER JOINed таблица c2 — нет. Таким образом, непроверенные данные все равно найдут все потенциальные повторяющиеся совпадения:

SELECT * FROM table t1
INNER JOIN table t2 ON t1.name = t2.name AND t1.id <> t2.id
WHERE t1.manually_verified = FALSE

Возможные совпадения для дубликатов будут в объединенной таблице.

person wuputah    schedule 18.09.2010
comment
Мне нравится ваш подход, но использование модифицированного запроса, который вы предлагаете, показывает только новую, непроверенную запись, а не любые записи, которые кажутся дубликатами. В противном случае, я думаю, этот метод сработал бы. - person pbarney; 19.09.2010
comment
Добавил запрос в конец ответа. - person wuputah; 20.09.2010