Найти последнюю запись в цепочке - процесс объединения клиентов - PullRequest
0 голосов
/ 02 января 2019

Я импортирую данные о клиентах из системы другого поставщика, и у нас есть процессы слияния, которые мы используем для выявления потенциальных дубликатов учетных записей клиентов, и они объединяют их, если они удовлетворяют определенным критериям - таким как то же имя, фамилия, SSN и DOB.В этом процессе я вижу, где мы создаем цепочки - например, клиент A объединяется с клиентом B, который затем объединяется с клиентом C.

Что я надеюсь сделать, чтобы идентифицировать эти цепочки и обновитьзапись клиента, указывающая на последнюю запись в цепочке.Таким образом, в моем примере выше, клиент A и клиент B будут иметь идентификатор клиента C в своем поле слияния с.

CustID FName   LName     CustStatusType  isMerged  MergedTo
1      Kevin   Smith     M               1         2 
2      Kevin   Smith     M               1         3
3      Kevin   Smith     M               1         4
4      Kevin   Smith     O               0         NULL
5      Mary    Jones     O               0         NULL
6      Wyatt   Earp      M               1         7
7      Wyatt   Earp      O               1         NULL
8      Bruce   Wayn      M               1         10
9      Brice   Wayne     M               1         10
10     Bruce   Wane      M               1         11
11     Bruce   Wayne     O               1         NULL

CustStatusType указывает, открыт ли счет клиента («O») или объединен («M»).«).И затем у нас есть поле isMerged в качестве поля BIT, которое указывает, была ли учетная запись объединена, и, наконец, поле MergedTo, которое указывает, к какой учетной записи клиента была присоединена запись.

С предоставленным примером, что бы я хотелчтобы достичь, чтобы записи CustID 1 и 2 имели запись MergedTo, установленную на 3, тогда как CustID 3 можно либо обновить, либо оставить как есть.Для идентификаторов Cust 4, 5 и 6 - эти записи находятся и не нуждаются в обновлении.Но для идентификаторов Cust 8 - 10 мне бы хотелось, чтобы эти записи были установлены на 11 - как в таблице ниже.

CustID FName   LName     CustStatusType  isMerged  MergedTo
1      Kevin   Smith     M               1         4 
2      Kevin   Smith     M               1         4
3      Kevin   Smith     M               1         4
4      Kevin   Smith     O               0         NULL
5      Mary    Jones     O               0         NULL
6      Wyatt   Earp      M               1         7
7      Wyatt   Earp      O               1         NULL
8      Bruce   Wayn      M               1         11
9      Brice   Wayne     M               1         11
10     Bruce   Wane      M               1         11
11     Bruce   Wayne     O               1         NULL

Я не смог выяснить, как этого добиться с помощью TSQL - предложения?

Данные испытаний:

DROP TABLE IF EXISTS #Customers;

CREATE TABLE #Customers
    (
        CustomerID INT ,
        FirstName VARCHAR (25) ,
        LastName VARCHAR (25) ,
        CustomerStatusTypeID VARCHAR (1) ,
        isMerged BIT ,
        MergedTo INT
    );
INSERT INTO #Customers
VALUES ( 1, 'Kevin', 'Smith', 'M', 1, 2 ) ,
       ( 2, 'Kevin', 'Smith', 'M', 1, 3 ) ,
       ( 3, 'Kevin', 'Smith', 'M', 1, 4 ) ,
       ( 4, 'Kevin', 'Smith', 'O', 0, NULL ) ,
       ( 5, 'Mary', 'Jones', 'O', 0, NULL ) ,
       ( 6, 'Wyatt', 'Earp', 'M', 1, 7 ) ,
       ( 7, 'Wyatt', 'Earp', 'O', 1, NULL ) ,
       ( 8, 'Bruce', 'Wayn', 'M', 1, 10 ) ,
       ( 9, 'Brice', 'Wayne', 'M', 1, 10 ) ,
       ( 10, 'Bruce', 'Wane', 'M', 1, 11 ) ,
       ( 11, 'Bruce', 'Wayne', 'O', 1, NULL );

SELECT *
FROM   #Customers;

DROP TABLE #Customers;

Ответы [ 3 ]

0 голосов
/ 02 января 2019

Рекурсию можно использовать для этого:

WITH CTE as
(
  SELECT P.CustomerID, P.MergedTo, CAST(P.CustomerID AS VarChar(Max)) as Levels
  FROM #Customers P
  WHERE P.MergedTo IS NULL

  UNION ALL

  SELECT  P1.CustomerID, P1.MergedTo, M.Levels + ', ' + CAST(P1.CustomerID AS VarChar(Max)) 
  FROM #Customers P1  
  INNER JOIN CTE M ON M.CustomerID = P1.MergedTo
 )
SELECT
       CustomerID
     , MergedTo 
     , x           -- "end of chain"
     , Levels
FROM CTE
CROSS APPLY (
    SELECT LEFT(levels,charindex(',',levels+',')-1) x
    ) a
WHERE MergedTo IS NOT NULL

Результат:

+----+------------+----------+----+------------+
|    | CustomerID | MergedTo | x  |   levels   |
+----+------------+----------+----+------------+
|  1 |         10 |       11 | 11 | 11, 10     |
|  2 |          8 |       10 | 11 | 11, 10, 8  |
|  3 |          9 |       10 | 11 | 11, 10, 9  |
|  4 |          6 |        7 |  7 | 7, 6       |
|  5 |          3 |        4 |  4 | 4, 3       |
|  6 |          2 |        3 |  4 | 4, 3, 2    |
|  7 |          1 |        2 |  4 | 4, 3, 2, 1 |
+----+------------+----------+----+------------+

Обратите внимание, что строка levels образована рекурсией, и таким образом она объединяетсяпервой частью будет «конец цепи» (см. столбец x).Эта первая часть извлекается с использованием перекрестного применения, хотя использование применения не является обязательным.

Доступен как demo

0 голосов
/ 02 января 2019

Ниже запрос находит последнюю CustomerID, которая соответствует каждому клиенту, и возвращает идентификатор в Ref столбце

select *
, Ref = (select top 1 CustomerID from #Customers where soundex(FirstName) = soundex(ma.FirstName) and soundex(LastName) = soundex(ma.LastName) order by CustomerID desc)
from #Customers ma

используя приведенное ниже обновление, вы можете обновить столбец MergedTo

;with ct as (
select *
, Ref = (select top 1 CustomerID from #Customers where soundex(FirstName) = soundex(ma.FirstName) and soundex(LastName) = soundex(ma.LastName) order by CustomerID desc)
from #Customers ma
)
update c1
set c1.MergedTo = iif(c1.CustomerID = ct.Ref, null, ct.Ref)
from #Customers c1
    inner join ct on ct.CustomerID = c1.CustomerID

Окончательные данные в таблице клиентов после обновления

Final Result

0 голосов
/ 02 января 2019

Для вашего примера soundex() кажется достаточно хорошим.Возвращает код, основанный на произношении слова на английском языке.Используйте его по имени и фамилии, чтобы присоединиться к таблице клиентов и подзапросу, который запрашивает таблицу клиентов, добавляя row_number(), разделенный по Soundex имен и порядков, по убыванию идентификатора - для нумерации «последней» записи с 1. Для условия соединения используйте Soundex имен, номер строки 1 и, конечно, неравенство идентификаторов.

UPDATE c1
       SET c1.mergedto = x.customerid
       FROM #customers c1
            LEFT JOIN (SELECT c2.customerid,
                              soundex(c2.firstname) sefn,
                              soundex(c2.lastname) seln,
                              row_number() OVER (PARTITION BY soundex(c2.firstname),
                                                              soundex(c2.lastname)
                                                 ORDER BY c2.customerid DESC) rn
                              FROM #customers c2) x
                      ON x.sefn = soundex(c1.firstname)
                         AND x.seln = soundex(c1.lastname)
                         AND x.rn = 1
                         AND x.customerid <> c1.customerid;

db <> fiddle

Я не совсем понимаю концепцию, стоящую за столбцами customerstatustypeid и ismerged.Как я понимаю, все они получены из того, является ли mergedto нулевым или нет.Но данные образца, ни ожидаемый результат не подтверждают это.Но так как эти столбцы, по-видимому, не меняются между вашими примерами ввода и вывода, я думаю, что все в порядке, я просто оставил их в покое.

Если Soundex окажется недостаточно для ваших нужд, вы можете захотеть поискать другую строкуметрики расстояния, такие как расстояние Левенштейна .Насколько нам известно, в SQL Server нет реализации, включенной в SQL Server, но поисковые системы могут выдавать реализации третьим сторонам или, может быть, есть что-то, что можно использовать через CLR.Или, конечно, вы делаете свой собственный.

...