簡體   English   中英

SQL CTE比較同一表中的行

[英]SQL CTE compare rows in the same table

我有一張桌子,上面有來自不同數據源的客戶。 有SSN,License#和一些唯一的ID,但並非所有來源都具有相同的ID。 我想比較ID列(SSN,License,SystemID)上的記錄,如果找到同一個人,則分配一個映射的ID。

我假設我可以使用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

這可能是解決問題的“足夠好”的方法。

沿着這三個維度中的每一個,找到該維度的最小行ID(對NULL進行特殊處理)。 然后,總的客戶標識符是這三個ID中的最小值。 要使其連續無間隙,請使用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以獲取不同維度上的最小id。 這樣的迭代可以快速連接不同的部分。 編寫遞歸CTE可能會做同樣的事情。 但是,上述更簡單的解決方案可以解決您的問題。

編輯:

因為我以前曾遇到過此問題,所以我想提出一個單一的查詢解決方案(而不是遍歷更新)。 使用遞歸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;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM