在 SQL 服务器中仅使用一次记录查找匹配对
Finding Matched Pairs using each record only once in SQL Server
我需要在 SQL 服务器中找到匹配的记录对,但每条记录只能包含在 1 对 中。一旦一条记录与一对匹配,就应该将其从任何未来对的考虑中删除。
我已经尝试了涉及 ROW_NUMBER()
和 LEAD()
的解决方案,但我无法完全做到。
这将用于根据多个客户属性(例如信用评分、收入等)将金融账户与类似账户配对以供审核。
声明:
declare @test table (ID numeric, Color varchar(20))
insert into @test values
(1,'Blue'),(2,'Red'),(3,'Blue'),(4,'Yellow'),(5,'Blue'),(6,'Red')
select*
from @test t1
join @test t2
on t1.Color = t2.Color
and t1.ID < t2.ID -----removes reverse-pairs and self-pairs
当前结果:
ID Color ID Color
--- ------- --- --------
1 Blue 3 Blue
1 Blue 5 Blue -----should not appear because 1 has already been paired
3 Blue 5 Blue -----should not appear because 3 and 5 have already been paired
2 Red 6 Red
需要的结果:
ID Color ID Color
--- ------- --- --------
1 Blue 3 Blue
2 Red 6 Red
您可以使用 row_number()
和条件聚合:
select
max(case when rn % 2 = 0 then id end) id1,
max(case when rn % 2 = 0 then color end) color1,
max(case when rn % 2 = 1 then id end) id2,
max(case when rn % 2 = 1 then color end) color2
from (
select
t.*,
row_number() over(partition by color order by id) - 1 rn
from @test t
) t
group by color, rn / 2
having count(*) = 2
子查询通过递增id
对具有相同color
的记录进行排名。然后,外部查询成对分组,并过滤包含两条记录的组。
id1 | color1 | id2 | color2
:-- | :----- | :-- | :-----
1 | Blue | 3 | Blue
2 | Red | 6 | Red
编辑最多评论
这是完成此操作的一种方法..
我首先根据颜色对记录进行排序,最低 ID 为 rnk=1,下一个为 rnk=2。
之后,我通过拉取 rnk=1 记录然后加入 rnk=2 将表连接在一起。
declare @test table (ID numeric, Color varchar(20))
insert into @test values
(1,'Blue'),(2,'Red'),(3,'Blue'),(4,'Yellow'),(5,'Blue'),(6,'Red'),(7,'Blue')
;with data
as (select row_number() over(partition by color order by id asc) as rnk
,color
,id
from @test
)
select a.id,a.color,b.id,b.color
from data a
join data b
on a.Color=b.Color
and b.rnk=a.rnk+1
where a.rnk%2=1
我得到如下输出
+----+-------+----+-------+
| id | color | id | color |
+----+-------+----+-------+
| 1 | Blue | 3 | Blue |
| 5 | Blue | 7 | Blue |
| 2 | Red | 6 | Red |
+----+-------+----+-------+
我需要在 SQL 服务器中找到匹配的记录对,但每条记录只能包含在 1 对 中。一旦一条记录与一对匹配,就应该将其从任何未来对的考虑中删除。
我已经尝试了涉及 ROW_NUMBER()
和 LEAD()
的解决方案,但我无法完全做到。
这将用于根据多个客户属性(例如信用评分、收入等)将金融账户与类似账户配对以供审核。
声明:
declare @test table (ID numeric, Color varchar(20))
insert into @test values
(1,'Blue'),(2,'Red'),(3,'Blue'),(4,'Yellow'),(5,'Blue'),(6,'Red')
select*
from @test t1
join @test t2
on t1.Color = t2.Color
and t1.ID < t2.ID -----removes reverse-pairs and self-pairs
当前结果:
ID Color ID Color
--- ------- --- --------
1 Blue 3 Blue
1 Blue 5 Blue -----should not appear because 1 has already been paired
3 Blue 5 Blue -----should not appear because 3 and 5 have already been paired
2 Red 6 Red
需要的结果:
ID Color ID Color
--- ------- --- --------
1 Blue 3 Blue
2 Red 6 Red
您可以使用 row_number()
和条件聚合:
select
max(case when rn % 2 = 0 then id end) id1,
max(case when rn % 2 = 0 then color end) color1,
max(case when rn % 2 = 1 then id end) id2,
max(case when rn % 2 = 1 then color end) color2
from (
select
t.*,
row_number() over(partition by color order by id) - 1 rn
from @test t
) t
group by color, rn / 2
having count(*) = 2
子查询通过递增id
对具有相同color
的记录进行排名。然后,外部查询成对分组,并过滤包含两条记录的组。
id1 | color1 | id2 | color2 :-- | :----- | :-- | :----- 1 | Blue | 3 | Blue 2 | Red | 6 | Red
编辑最多评论
这是完成此操作的一种方法..
我首先根据颜色对记录进行排序,最低 ID 为 rnk=1,下一个为 rnk=2。
之后,我通过拉取 rnk=1 记录然后加入 rnk=2 将表连接在一起。
declare @test table (ID numeric, Color varchar(20))
insert into @test values
(1,'Blue'),(2,'Red'),(3,'Blue'),(4,'Yellow'),(5,'Blue'),(6,'Red'),(7,'Blue')
;with data
as (select row_number() over(partition by color order by id asc) as rnk
,color
,id
from @test
)
select a.id,a.color,b.id,b.color
from data a
join data b
on a.Color=b.Color
and b.rnk=a.rnk+1
where a.rnk%2=1
我得到如下输出
+----+-------+----+-------+
| id | color | id | color |
+----+-------+----+-------+
| 1 | Blue | 3 | Blue |
| 5 | Blue | 7 | Blue |
| 2 | Red | 6 | Red |
+----+-------+----+-------+