按逻辑定义行组

时间:2017-04-09 09:00:17

标签: sql sql-server

我有一个独特的场景,我无法找到解决方案,所以我想问专家:)

我有一个返回课程大纲的查询,每行代表一天的培训。您可以在下面的图片中看到培训中间有休息日

我无法找到将每个连续培训日分组的方法

请参阅下面的截图详细说明行和我想要实现的目标

我正在使用MS-SQL 2014

这是一个关于我拥有的数据和预期结果的小提琴 SQL Fiddle

enter image description here

2 个答案:

答案 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正在使用laglead函数来捕获上一行和下一行值。然后我们采取天差并使用和捕获差异不是1的日期。这些是组应该切换的日期。使用派生表dd。

现在将其与主表交叉连接并使用聚合函数来确定连续组(花了我很多命中和试验)来实现这一点。

然后使用dense_rank函数获取该组。