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. Този тригер/процедура съвпада с комбинацията FIRST + LAST име на "Inserted" запис с всички съществуващи записи в таблицата.
  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

напр.: Нов потребител John Doe - (ID 345) - 3 потенциални съвпадения John Doe - ID 123 ID 231 / ID 256

Администраторът ще провери данните за 345 спрямо данните в 123 / 231 и 256 и ще потвърди ръчно дали има дубликат на ВСЯКО / Няма Ако дубликат, 345 се изтрива от таблицата с потребители (меко / твърдо изтриване - каквото ви подхожда) Ако НЕ, записите за ID 354 току-що са премахнати от MatchingTable (аз бих използвал твърди изтривания тук, тъй като това е като транзакционна временна таблица, но отново всичко е наред).

Освен това, когато записи за ID 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, ако ръчно сте проверили данните. След това можете просто да поискате where 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