Многократная идентификация дублирования с исключениями - PullRequest
0 голосов
/ 12 октября 2019

У меня есть таблица клиентов с несколькими сотнями тысяч записей. Есть много дубликатов различной степени. Я пытаюсь идентифицировать дубликаты записей с уровнем вероятности дублирования.

Моя исходная таблица имеет 7 полей и выглядит следующим образом: Sample Source Table

Я смотрюдля дубликатов и поместите их в промежуточную таблицу с указанием уровня вероятности, имени таблицы и номера клиента. Промежуточная таблица

CREATE TABLE DataCheck (
    id          int             identity(1,1),
    reason      varchar(100)    DEFAULT NULL,
    tableName   varchar(100)    DEFAULT NULL,
    tableID     varchar(100)    DEFAULT NULL
)

Вот мой код для идентификации и вставки:

-- Match on Company, Contact, Address, City, and Phone
-- DUPE
INSERT INTO DataCheck 
    SELECT 'Duplicate','CUSTOMER',tcd.uid
      FROM #tmpCoreData tcd
        INNER JOIN 
        (SELECT
            company, 
            fname,
            lname,
            add1,
            city,
            phone1,
            COUNT(*) AS count
          FROM #tmpCoreData
          WHERE company <> ''
          GROUP BY company, fname, lname, add1, city, phone1
          HAVING COUNT(*) > 1) dl 
        ON dl.company = tcd.company
    ORDER BY tcd.company

В этом примере он будет вставлять идентификаторы 101, 102

Проблема заключается в том, когдаЯ выполняю следующий проход:

-- Match on Company, Address, City, Phone (Diff Contacts)
-- LIKELY DUPE
INSERT INTO DataCheck 
    SELECT 'Likely Duplicate','CUSTOMER',tcd.uid
      FROM #tmpCoreData tcd
        INNER JOIN 
        (SELECT
            company, 
            add1,
            city,
            phone1,
            COUNT(*) AS count
          FROM #tmpCoreData
          WHERE company <> ''
          GROUP BY company, add1, city, phone1
          HAVING COUNT(*) > 1) dl 
        ON dl.company = tcd.company
    ORDER BY tcd.companyc

Этот проход затем вставит 101, 102 и 103. На следующем проходе телефон будет сброшен, и он вставит 101, 102, 103, 104. Следующий проход будет искатьтолько для компании, которая вставила бы все 5.

Теперь у меня есть 14 записей в моей промежуточной таблице для 5 записей.

Как добавить исключение, чтобы группы 2-го прохода в одной компании, адресе, Город, телефон, но разные имена и имена. Тогда он должен только вставить 101 и 103

Я рассмотрел добавление NOT IN (SELECT tableID FROM DataCheck), чтобы идентификаторы не добавлялись несколько раз, но на 3-м и 4-м проходах он может найти дубликат и ввести700 записей после строки это дубликат, так что вы теряете контекст этого дублирования.

Мой вывод использует:

SELECT 
    dc.reason,
    dc.tableName,
    tcd.*
  FROM DataCheck dc
  INNER JOIN #tmpCoreData tcd
    ON tcd.uid = dc.tableID
ORDER BY dc.id

И выглядит примерно так, что немногосбивает с толку: Output Table

1 Ответ

2 голосов
/ 12 октября 2019

Я собираюсь оспорить ваше восприятие вашей проблемы и вместо этого предлагаю вам рассчитать простой «показатель доверия», который также поможет вам значительно упростить таблицу результатов:

WITH FirstCompany AS (SELECT custNo, company, fname, lname, add1, city, phone1
                      FROM(SELECT custNo, company, fname, lname, add1, city, phone1, 
                                  ROW_NUMBER() OVER(PARTITION BY company ORDER BY custNo) AS ordering
                           FROM CoreData) FC
                      WHERE ordering = 1)

SELECT RankMapping.description, Duplicate.custNo, Duplicate.company, Duplicate.fname, Duplicate.lname, Duplicate.add1, Duplicate.city, Duplicate.phone1
FROM (SELECT FirstCompany.custNo AS originalCustNo, Duplicate.*, 
             CASE WHEN FirstCompany.custNo = Duplicate.custNo THEN 1 ELSE 0 END 
             + CASE WHEN FirstCompany.fname = Duplicate.fname AND FirstCompany.lname = Duplicate.lname THEN 1 ELSE 0 END 
             + CASE WHEN FirstCompany.add1 = Duplicate.add1  AND FirstCompany.city = Duplicate.city THEN 1 ELSE 0 END
             + CASE WHEN FirstCompany.phone1 = Duplicate.phone1 THEN 1 ELSE 0 END
             AS ranking
      FROM FirstCompany
      JOIN CoreData Duplicate
        ON Duplicate.custNo >= FirstCompany.custNo
           AND Duplicate.company = FirstCompany.company) Duplicate
JOIN (VALUES (4, 'original'),
             (3, 'duplicate'),
             (2, 'likely dupe'),
             (1, 'possible dupe'),
             (0, 'not likely dupe')) RankMapping(score, description)
 ON RankMapping.score = Duplicate.ranking
ORDER BY Duplicate.originalCustNo, Duplicate.ranking DESC

Пример SQL Fiddle

..., который генерирует результаты, которые выглядят следующим образом:

| description     | custNo | company  | fname   | lname  | add1         | city         | phone1     |
|-----------------|--------|----------|---------|--------|--------------|--------------|------------|
| original        | 101    | ACME INC | JOHN    | DOE    | 123 ACME ST  | LOONEY HILLS | 1231234567 |
| duplicate       | 102    | ACME INC | JOHN    | DOE    | 123 ACME ST  | LOONEY HILLS | 1231234567 |
| likely dupe     | 103    | ACME INC | JANE    | SMITH  | 123 ACME ST  | LOONEY HILLS | 1231234567 |
| possible dupe   | 104    | ACME INC | BOB     | DOLE   | 123 ACME ST  | LOONEY HILLS | 4564567890 |
| not likely dupe | 105    | ACME INC | JESSICA | RABBIT | 456 ROGER LN | WARNER       | 4564567890 |

Этот код безосновательно предполагает, что наименьшее custNo«оригинал» и предполагает, что совпадения будут эквивалентны только этому, но вполне возможно получить и другие совпадения (просто отмените вложенный запрос в CTE и удалите номер строки).

...