我想根据两列将我的日期重组为群组。下面的数据显示了我的数据。我不能给你发一张漂亮的照片,因为我是新来的,但简历应该足够清楚了。
+-----+-----+--------+
| X1 | X2 | Result |
+-----+-----+--------+
| 4 | 1 | A |
| 4 | 2 | A |
| 1 | 3 | B |
| 2 | 3 | B |
| 3 | 4 | C |
| 3 | 5 | C |
| 1 | 6 | B |
| 2 | 6 | B |
+-----+-----+--------+
我有两列表示我的数据所属的类别。我想将它们重新组合成一个组,在这组中他们都属于一个组别或另一个组。我想找到一个有效的查询。
目前,我已经考虑过建立一个连接,将哪个元素链接到哪个元素:
SELECT * FROM [Table] T1
JOIN [Table] T2 ON T1.Gr1 = T2.Gr1 OR T1.Gr2 = T2.Gr2
有了这个,我可以构建一个以第一个元素开头的递归查询,如果它以某种方式链接到另一个组,则将另一个添加到另一个组中,如果没有,则将其添加到新的等级。有了大量的数据,它看起来并不优雅也没有效率。
任何人都有解决方案吗?
EDIT。我意识到我的问题不明确。每行有两个分类变量X1和X2。我想将所有共同观察中的所有观察结果分开。在例子中,B组保持所有具有X1 = 1或2或X2 = 3或6的观测值.C组保持观察结果x1 = 3且x2 = 4或5.我希望这使事情更清楚。
答案 0 :(得分:0)
我想我明白你想要达到的目标。
为了澄清,我认为您想要动态创建新组,因为某种指针会通过X1 / X2对列表。如果已经看到X1 OR X2,请将其添加到现有组,否则将其添加到新组。
这对于数据库端计算来说是相当不寻常的,因为它不属于RDBMS设计的常规基于集合的理论。例如:如果一个项目匹配位于不同组中的前两个行,那么该项目会进入哪个组?
这可以用光标完成,但我讨厌游标,所以我不会去那里(至少还没有)。我认为有一种方法可以通过window functions实现这一目标。
这是一个相当粗略的例子,说明如何实现它 - 请记住,这种逻辑的细微差别可能不符合您的预期,正如我上面的重复行注释。这假设输入数据具有某种有序/唯一键,通过行继续并根据需要创建新组,如果找到重复匹配,则它只匹配第一个实例。
在大型桌子上这可能非常慢(...所以用户要小心并且所有这些东西):
declare @t table (
i int identity, -- here's our ordered key
X1 int,
X2 int
);
-- Here's our test data (a few extra rows added on for good measure
insert into @t
values (4, 1),(4, 2),(1, 3),(2, 3),(3, 4),(3, 5),(1, 6),
(2, 6),(2, 1),(2, 2),(2, 5),(7, 7),(4, 1),(1, 2),
(9, 9),(9, 1)
; with cte as (
-- keep track of the newest group number (by summing the "new group" flags):
select i, X1, X2, sum(newgrp) over (order by i) newestGroupNo
from (
-- This subquery flags whenever there is a row that doesn't
-- match any previous row, and a new group should be created
select X1, X2, i,
case when
(count(*) over (partition by X1 order by i)) = 1 and -- unique over X1
(count(*) over (partition by X2 order by i)) = 1 -- unique over X2
then 1 -- New group
else 0 -- Existing group
end newgrp
from @t
) b
)
-- Now do the uniqueness check again, but either return the new group no,
-- or the group no of the first group that matches prior to this row
select i, X1, X2,
case when
(count(*) over (partition by X1 order by i)) = 1 and -- unique over X1
(count(*) over (partition by X2 order by i)) = 1 -- unique over X2
then newestGroupNo -- New group, return the group number
else (select top 1 newestGroupNo
from cte
where (cte.X1 = c.X1 or cte.X2 = c.X2) and cte.i <= c.i) -- Existing group
end grp
from cte c order by i
结果:
i X1 X2 grp
1 4 1 1 new group
2 4 2 1 match on X1 where i=1
3 1 3 2 no match
4 2 3 2 match on X2 where i=3
5 3 4 3 no match
6 3 5 3 match on X1 where i=5
7 1 6 2 match on X1 where i=3
8 2 6 2 match on X1 where i=4 (not i=7)
9 2 1 1 match on X2 where i=1 (not i=4 or i=8)
10 2 2 1 match on X2 where i=2 (... etc)
11 2 5 2 match on X1 where i=4
12 7 7 4 no match
13 4 1 1 match on X1 where i=1
14 1 2 1 match on X2 where i=2
15 9 9 5 no match
16 9 1 1 match on X2 where i=1
这是否符合您的期望?如果要处理大型表,请确保对此进行测试,在存储过程中几乎肯定有更快的方法可以实现此目的,但这会为您提供单个查询,如果需要,可以将其放入视图中。
欢迎对上述脚本进行改进。