[英]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.