首页 > 解决方案 > 没有重叠日期的 SQL 分组结果

问题描述

我有大量员工数据,其中包含许多与开始和结束日期相关联的键。我想将这些组合成一组在开始日期和结束日期之间没有重叠的唯一条目。例如,我希望我的输出如下所示。

EmpID   Name    Status  Team    Start   End
1   Zoe Employed    Team01  2018-01-01  2018-01-04
1   Zoe CareerBreak Team01  2018-01-05  2018-01-07
1   Zoe Employed    Team01  2018-01-08  2018-01-10
2   Bob Employed    Team01  2018-01-01  2018-01-03
2   Bob Employed    Team02  2018-01-04  2018-01-10

我可以通过以下形式之一轻松获取我的数据。

EmpID   Name    Status  Start   End
1   Zoe Employed    2018-01-01  2018-01-04
1   Zoe CareerBreak 2018-01-05  2018-01-07
1   Zoe Employed    2018-01-08  2018-01-10
1   Zoe Team01  2018-01-01  2018-01-10
2   Bob Employed    2018-01-01  2018-01-10
2   Bob Team01  2018-01-01  2018-01-03
2   Bob Team02  2018-01-04  2018-01-10

或者

EmpID   Name    Status  Team    Date
1   Zoe Employed    Team01  2018-01-01
1   Zoe Employed    Team01  2018-01-02
1   Zoe Employed    Team01  2018-01-03
1   Zoe Employed    Team01  2018-01-04
1   Zoe CareerBreak Team01  2018-01-05
1   Zoe CareerBreak Team01  2018-01-06
1   Zoe CareerBreak Team01  2018-01-07
1   Zoe Employed    Team01  2018-01-08
1   Zoe Employed    Team01  2018-01-09
1   Zoe Employed    Team01  2018-01-10
2   Bob Employed    Team01  2018-01-01
2   Bob Employed    Team01  2018-01-02
2   Bob Employed    Team01  2018-01-03
2   Bob Employed    Team02  2018-01-04
2   Bob Employed    Team02  2018-01-05
2   Bob Employed    Team02  2018-01-06
2   Bob Employed    Team02  2018-01-07
2   Bob Employed    Team02  2018-01-08
2   Bob Employed    Team02  2018-01-09
2   Bob Employed    Team02  2018-01-10

我已经能够通过遍历每个日期记录并进行比较来做到这一点。但这显然需要的时间太长了。

我在分组时遇到的问题是更改前后的细节是相同的。因此,从分组中排除日期以获取最小和最大日期给了我以下信息。

EmpID   Name    Status  Team    Start   End
1   Zoe Employed    Team01  2018-01-01  2018-01-10
1   Zoe CareerBreak Team01  2018-01-05  2018-01-07

这应该是 3 个条目。我想不出还有什么方法可以做到这一点,我很确定分组不是一个选择,但它可能是一个起点。我很乐意自己做这项研究,但我被困住了,需要一个关于看什么的提示,这可能会提供一个解决方案,以便在不重叠日期的情况下将其拆分。(显然这是一个非常简化的数据块,但希望它足以解释这个问题)

标签: sqlsql-server

解决方案


这是一个群岛问题。您可以通过从日期中减去一系列数字来解决它 - 这对于连续日期是恒定的。这使用您的数据的长格式:

select empid, name, status, team, min(date), max(date)
from (select t.*,
             row_number() over (partition by empid, status, team order by date) as seqnum
      from t
     ) t
group by empid, name, status, team, dateadd(day, -seqnum, date)
order by empid, min(date);

推荐阅读