Вот что может быть "достаточно хорошим" подход к проблеме.
В каждом из трех измерений найдите минимальный идентификатор строки для этих размеров (при специальной обработке NULL). Таким образом, общий идентификатор клиента является минимальным из этих трех идентификаторов. Чтобы сделать его последовательным без пробелов, используйте dense_rank()
.
with ids as (
select t.*,
(case when SSN is not null
then min(RowId) over (partition by SSN)
end) as SSN_id,
(case when License is not null
then min(RowId) over (partition by License)
end) as License_id,
(case when SystemId is not null
then min(RowId) over (partition by SystemId)
end)as SystemId_id
from t
),
leastid as (
select ids.*,
(case when SSN_Id <= coalesce(License_Id, SSN_Id) and
SSN_Id <= coalesce(SystemId_id, SSN_Id)
then SSN_Id
when License_Id <= coalesce(SystemId_id, License_Id)
then License_Id
else SystemId_id
end) as LeastId
from ids
)
select Source, RowID, SSN, License, SystemID,
dense_rank(LeastId) over (order by LeastId) as MapCustomerId
from LeastIds;
Это некое полное решение, но оно работает для ваших данных. Он не работает в следующем случае:
A |1 |SSN1|Lic111 | |1
A |2 |SSN1| |Sys666 |2
A |3 | | |Sys666 |2
Потому что для этого требуются два «прыжка».
Когда я столкнулся с такой ситуацией в прошлом, я создал дополнительный столбец в таблице и неоднократно использовал update
, чтобы получить минимальный идентификатор по разным размерам. Такая итерация быстро соединяет разные части. Вероятно, можно написать рекурсивный CTE, чтобы сделать то же самое. Но более простое решение выше может решить вашу проблему.
EDIT:
Потому что я сталкивался с этой проблемой раньше, я хотел, чтобы придумать с помощью единого решения запроса (а не перебором обновлений). Это возможно с использованием рекурсивных CTE. Вот код, который кажется сработал:
with t as (
select 'A' as source, 1 as RowId, 'SSN1' as SSN, 'Lic111' as License, 'ABC' as SystemId union all
select 'A', 2, 'SSN1', NULL, 'Sys666' union all
select 'A', 3, NULL, NULL, 'Sys666' union all
select 'A', 4, NULL, 'Lic222', 'Sys666' union all
select 'A', 5, NULL, 'Lic222', NULL union all
select 'A', 6, NULL, 'Lic444', NULL
),
first as (
select t.*,
(select min(RowId)
from t t2
where t2.SSN = t.SSN or
t2.License = t.License or
t2.SystemId = t.SystemId
) as minrowid
from t
),
cte as (
select rowid, minrowid
from first
union all
select cte.rowid, first.minrowid
from cte join
first
on cte.minrowid = first.rowid and
cte.minrowid > first.minrowid
),
lookup as (
select rowid, min(minrowid) as minrowid,
dense_rank() over (order by min(minrowid)) as MapCustomerId
from cte
group by rowid
)
select t.*, lookup.MapCustomerId
from t join
lookup
on t.rowid = lookup.rowid;
Спасибо Гордон. Это дает мне отличную отправную точку. У меня есть ситуация, о которой вы говорили о «двух прыжках» или даже больше. Можете ли вы объяснить немного больше? Я не уверен, что вы подразумеваете, вводя минимальный идентификатор в разные измерения. Я бы сравнил минимальный ID с столбцом MapCustID? Большое спасибо за помощь. – user2793572