我的分组情况很奇怪,在查找SQL分组的最佳方法时遇到了一些麻烦。
想象一下,我们有一张桌子
CREATE TABLE Item
(
KeyId VARCHAR(1) NOT NULL,
Col1 INT NULL,
Col2 INT NULL,
Col3 INT NULL
)
GO
INSERT INTO Item (KeyId, Col1, Col2, Col3)
VALUES
('a',1,2,3),
('b',5,4,3),
('c',5,7,6),
('d',8,7,9),
('e',11,10,9),
('f',11,12,13),
('g',20,22,21),
('h',23,22,24)
我需要将此表中的记录分组,以便如果两个记录的Col1 OR Col2 OR Col3相同,则这两个记录应该在同一组中,并且应该有链接。 换句话说,对于上述数据,记录“ a”(第一条记录)的Col3 = 3,而记录“ b”(第二条记录)的Col3 = 3,因此这两个应该在一组中。但是,记录“ b”与记录“ c”具有相同的Col1,因此记录“ c”应与“ a”和“ b”处于同一组。然后,记录“ d”与“ c”具有相同的Col2,因此它也应该在同一组中。同样,“ e”和“ f”在Col3和Col1中分别具有相同的值。
另一方面,记录“ g”和“ h”将在一个组中(因为它们具有相同的Col2 = 22),但是该组将与记录“ a”,“ b”的组不同, 'c','d','e','f'。
查询结果应该类似于
KeyId GroupId
'a' 1
'b' 1
'c' 1
'd' 1
'e' 1
'f' 1
'g' 2
'h' 2
也许可以通过一些循环/游标来做到这一点,但是我开始考虑更简洁的方式,这似乎很困难。
答案 0 :(得分:4)
您在这里:
with g (rootid, previd, level, keyid, col1, col2, col3) as (
select keyid, '-', 1, keyid, col1, col2, col3 from item
union all
select g.rootid, g.keyid, g.level + 1, i.keyid, i.col1, i.col2, i.col3
from g
join item i on i.col1 = g.col1 or i.col2 = g.col2 or i.col3 = g.col3
where i.keyid > g.keyid
),
m (keyid, rootid) as (
select keyid, min(rootid) from g group by keyid
)
select * from m;
结果:
keyid rootid
----- ------
a a
b a
c a
d a
e a
f a
g g
h g
注意:请记住,默认情况下,SQL Server在处理递归CTE时限制为100次迭代(每组行数)。 英语:即使如上所述可以执行此操作,SQL Server可以处理的内容也有明显的限制。如果达到此限制,您将收到消息:
在语句完成之前,最大递归100已用尽。
如果发生这种情况,请考虑添加条款option (maxrecursion 32767)
。