见上述数据。
对于每个学生,我需要得出学生在场的最后连续几天的计数。
有人可以就此提出想法吗?
;with CTE As
(select 1 as stdId, 1 as dt
union
select 1 as stdId, 2 as dt
union
select 1 as stdId, 3 as dt
union
select 1 as stdId, 5 as dt
union
select 1 as stdId, 6 as dt
union
select 1 as stdId, 7 as dt
union
select 1 as stdId, 9 as dt
union
select 2 as stdId, 2 as dt
union
select 2 as stdId, 4 as dt
union
select 2 as stdId, 7 as dt
union
select 2 as stdId, 8 as dt
)
select stdId, dt
FROM
CTE
答案 0 :(得分:2)
1)使用dt和rownumber的差异,根据存在的连续天数对组进行分类。
2)然后获得每个学生的最后一组和每组的计数。
3)最后选择每个学生最后一组的计数。
select distinct stdid,cnt
from (select stdid,grp,count(*) over(partition by stdid,grp) cnt,
max(grp) over(partition by stdid) lastgrp
from (select stdId, dt,dt-row_number() over(partition by stdid order by dt) grp
FROM CTE) x
) y where lastgrp=grp
<强> Sample Demo
强>
答案 1 :(得分:2)
一种方法是使用recursive cte。
这项技术从顶部开始向下,一直向下,直到找不到更多匹配。
;with CTE As
(
select 1 as stdId, 1 as dt
union
select 1 as stdId, 2 as dt
union
select 1 as stdId, 3 as dt
union
select 1 as stdId, 5 as dt
union
select 1 as stdId, 6 as dt
union
select 1 as stdId, 7 as dt
union
select 1 as stdId, 9 as dt
union
select 2 as stdId, 2 as dt
union
select 2 as stdId, 4 as dt
union
select 2 as stdId, 7 as dt
union
select 2 as stdId, 8 as dt
),
CTEr AS
(
-- Use recursiion, starting at the top and working down by one.
-- Anchor part.
SELECT
stdId,
MAX(dt) AS dt
FROM
CTE
GROUP BY
stdId
UNION ALL
-- Recursive part.
SELECT
r.stdId,
r.dt -1 AS dt
FROM
CTEr AS r
INNER JOIN CTE AS c ON c.stdId = r.stdId
AND c.dt = r.dt -1
)
select
stdId,
COUNT(dt) AS Result
FROM
CTEr
GROUP BY
stdId
;
使用递归时性能可能是一个问题,尤其是对于较大的数据集。如果是这种情况,我建议使用@ vkp的方法。
答案 2 :(得分:0)
如果你想要1为学生1(&#34; 9&#34;)和&#34; 2&#34;对于学生2(&#34; 7&#34;和&#34; 8&#34;)然后:
select top (1) with ties t.*
from (select cte.*,
row_number() over (partition by stdid order by date) as seqnum
from cte
where student = @student
) t
order by (dt - seqnum) desc;
这是做什么的?首先,它为每个学生生成一个序列号。这与dt
列之间的差异是&#34; dt&#34;的连续值的常量。
然后,它只是按差异排序并获得具有最大差异的所有行。这些是最后的连续行。
这确实有两个假设:
dt
的最高值,而不是某个总体最高值。这些是基于问题和问题数据的合理假设。处理其他情况有很简单的替代方案。
最后,请注意,如果您的数据看起来更像图片而不是CTE,那么转换它的简单方法是:
select top (1) with ties t.*
from (select cte.*,
row_number() over (partition by stdid order by date) as seqnum
from t cross apply
(values (t.[1]), (t.[2]), . . . ) v(dt)
where student = @student and v.dt = 'yes'
) t
order by (dt - seqnum) desc;