Создание единого идентификатора для любой комбинации совпадений между тремя разными идентификаторами
У меня есть данные о клиентах, поступающие из нескольких разных систем, с тремя потенциальными уникальными идентификаторами. Нам нужно создать один новый идентификатор, который можно использовать для связи ЛЮБОГО совпадения между тремя идентификаторами.
Данные имеют следующую структуру:
Я попытался создать список всех возможных совпадений, как показано ниже, но я не уверен, как объединить его в единый идентификатор для каждого клиента.
DROP TABLE IF EXISTS #Test
CREATE TABLE #Test (PrimaryKey int, CustomerID1 varchar(15), CustomerID2 varchar(15), CustomerID3 varchar(15))
INSERT INTO #Test VALUES
(1,'Alpha','Dog','Jeans')
,(2,'Alpha','Cat','Shirt')
,(3,'Beta','Dog','Dress')
,(4,'Gamma','Bear','Jeans')
,(5,'Alpha','Dog','Jeans')
,(6,'Epsilon','Bird','Boots')
SELECT
t1.PrimaryKey
,t2.Primarykey
FROM #Test t1
JOIN #Test t2 on t2.PrimaryKey != t1.PrimaryKey and t1.CustomerID1 = t2.CustomerID1
UNION
SELECT
t1.PrimaryKey
,t2.Primarykey
FROM #Test t1
JOIN #Test t2 on t2.PrimaryKey != t1.PrimaryKey and t1.CustomerID2 = t2.CustomerID2
UNION
SELECT
t1.PrimaryKey
,t2.Primarykey
FROM #Test t1
JOIN #Test t2 on t2.PrimaryKey != t1.PrimaryKey and t1.CustomerID3 = t2.CustomerID3
Я чувствую, что решение очевидно, но я застрял, поэтому любая помощь приветствуется! Спасибо!
1 ответ
Это немного сложно сделать за один выбор (по крайней мере, для меня). Я обычно делаю что-то вроде этого:
SELECT *, CAST(NULL AS INT) AS ID_To
INTO #t
FROM
(
VALUES (1, N'Alpha', N'Dog', N'Jeans')
, (2, N'Alpha', N'Cat', N'Shirt')
, (3, N'Beta', N'Dog', N'Dress')
, (4, N'Gamma', N'Bear', N'Jeans')
, (5, N'Alpha', N'Dog', N'Jeans')
, (5, N'Alpha', N'Bonanza', N'Boots')
, (6, N'Epsilon', N'Bird', N'Boots')
, (7, N'zz', N'dog', N'Bird')
, (8, N'zzz', N'bye', N'hi')
, (9, N'zzzz', N'bear', N'hi ho silver')
) t (ID,CustomerID1,CustomerID2,CustomerID3)
WHILE @@rowcount > 0
BEGIN
UPDATE t2
SET ID_to = ISNULL(t.ID_To, t.ID)
FROM #t t
LEFT JOIN #t tTo
ON tTo.ID = t.ID_To
CROSS APPLY (
VALUES (t.Customerid1), (t.Customerid2), (t.Customerid3)
) v(externalId)
CROSS JOIN #t t2
CROSS APPLY (
VALUES (t2.Customerid1), (t2.Customerid2), (t2.Customerid3)
) v2(externalId)
WHERE ISNULL(t.id_To, t.id) < ISNULL(t2.ID_to, t2.id)
AND v.externalId = v2.externalId
AND t.ID <> t2.ID
END
SELECT *
FROM #t
SELECT ISNULL(ID_TO, ID) AS groups
FROM #t
GROUP BY ISNULL(ID_TO, ID)
Чтобы объяснить код:
- Я создаю два столбца в вашей таблице, содержащие идентификатор строки (ID) и идентификатор возможного совпадения (ID_to). Это позволяет нам консолидировать то, как каждый клиент сопоставляется с другими клиентами.
- Потом делаю петлю. В цикле я пытаюсь сопоставить ключи между двумя разными клиентами. Что я хочу сделать, так это сопоставить каждого клиента с другим идентификатором клиента1,2,3 (И v.externalId = v2.externalId )
- Чтобы убедиться, что цикл завершен, я хочу только сопоставить, если новый идентификатор ниже текущего ISNULL(t.id_To, t.id) < ISNULL(t2.ID_to, t2.id). Если соответствующий клиент уже сопоставлен с кем-то другим, я беру его ID_to. Это гарантирует, что если есть длинная цепочка совпадающих идентификаторов, мы будем следовать всей цепочке.
- Трюк WHILE @@ROWCOUNT > 0 весьма полезен для зацикливания до тех пор, пока не будет что делать. Но на самом деле важно иметь условие прерывания, иначе цикл будет работать вечно.
Вы можете поместить выборку в цикл while, чтобы отслеживать, что происходит с #t-таблицей.
Когда цикл завершен, каждый клиент должен иметь либо ID_to = NULL, что означает, что он является «главным», либо ID_to > 0, что означает, что этот клиент сопоставляется с другим основным клиентом.