2013-12-20 8 views
0

У меня есть таблица с клиентами из разных источников данных. Существуют SSN, лицензия # и некоторые уникальные идентификаторы, но не все источники имеют одинаковые идентификаторы. Я хотел бы сравнить записи в столбцах ID (SSN, License, SystemID) и назначить сопоставленный идентификатор, если тот же человек найден.SQL CTE сравнить строки в одной таблице

Я предполагаю, что могу использовать CTE, но не знаю, с чего начать. Все еще пытаюсь учиться в SQL. Любая помощь будет оценена. Благодарю.

Это как таблица выглядит:

Source|RowID|SSN |License|SystemID 
A  |1 |SSN1|Lic111 | 
A  |2 | |  |Sys666 
B  |3 |SSN2|  |Sys777 
C  |4 |SSN1|  | 
D  |5 | |Lic333 | 
D  |6 | |Lic333 |Sys666 
E  |7 | |  |Sys777 

Результаты (добавлены MapCustomerID)

Source|RowID|SSN |License|SystemID|MapCustomerID 
A  |1 |SSN1|Lic111 |  |1 
A  |2 | |  |Sys666 |2 
B  |3 |SSN2|  |Sys777 |3 
C  |4 |SSN1|  |  |1 
D  |5 | |Lic999 |  |4 
D  |6 | |Lic333 |Sys666 |2 
E  |7 | |  |Sys777 |3 

ответ

1

Вот что может быть "достаточно хорошим" подход к проблеме.

В каждом из трех измерений найдите минимальный идентификатор строки для этих размеров (при специальной обработке 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; 
+0

Спасибо Гордон. Это дает мне отличную отправную точку. У меня есть ситуация, о которой вы говорили о «двух прыжках» или даже больше. Можете ли вы объяснить немного больше? Я не уверен, что вы подразумеваете, вводя минимальный идентификатор в разные измерения. Я бы сравнил минимальный ID с столбцом MapCustID? Большое спасибо за помощь. – user2793572

Смежные вопросы