我有一个独特的场景,我无法找到解决方案,所以我想问专家:)
我有一个返回课程大纲的查询,每行代表一天的培训。您可以在下面的图片中看到培训中间有休息日
我无法找到将每个连续培训日分组的方法
请参阅下面的截图详细说明行和我想要实现的目标
我正在使用MS-SQL 2014
这是一个关于我拥有的数据和预期结果的小提琴 SQL Fiddle
答案 0 :(得分:3)
最简单的方法是row_number()
的差异。以下标识每个具有数字的连续组:
select td.*,
dense_rank() over (order by dateadd(day, - seqnum, DayOfTraining)) as grpnum
from (select td.*,
row_number() over (order by DayOfTraining) as seqnum
from TrainingDays td
) td;
关键的想法是从连续日减去一个序列会在那些日子里产生一个常数。
Here是SQL小提琴。
答案 1 :(得分:0)
经过多次打击和试验,这是我能提出的最接近的
http://rextester.com/ECBQ88563
这里的问题是,如果最后一行属于另一个组,它仍然会将它与前一个组一起使用。因此,如果您将上次日期从19更改为20,则在您的示例中,输出仍将是相同的。可能与另一个条件,我们可以消除它。除此之外,这应该有效。
SELECT DayOfTraining1,
dense_rank() over (ORDER BY grp_dt) AS grp
FROM
(SELECT DayOfTraining1,
min(DayOfTraining) AS grp_dt
FROM
(SELECT trng.DayOfTraining AS DayOfTraining1,
dd.DayOfTraining
FROM trng
CROSS JOIN
(SELECT d.*
FROM
(SELECT trng.*,
lag (DayOfTraining,1) OVER (
ORDER BY DayOfTraining) AS nxt_DayOfTraining,
lead (DayOfTraining,1) OVER (
ORDER BY DayOfTraining) AS prev_DayOfTraining,
datediff(DAY, lag (DayOfTraining,1) OVER (
ORDER BY DayOfTraining), DayOfTraining) AS ddf
FROM trng
) d
WHERE d.ddf <> 1
OR prev_DayOfTraining IS NULL
) dd
WHERE trng.DayOfTraining <= dd.DayOfTraining
) t
GROUP BY DayOfTraining1
) t1;
说明:内部查询d
正在使用lag
和lead
函数来捕获上一行和下一行值。然后我们采取天差并使用和捕获差异不是1的日期。这些是组应该切换的日期。使用派生表dd。
现在将其与主表交叉连接并使用聚合函数来确定连续组(花了我很多命中和试验)来实现这一点。
然后使用dense_rank
函数获取该组。