查找每个员工的项目开始日期和结束日期(即开始日期和结束日期应该是连续的,在天/月/年中没有任何中断)

Posted

技术标签:

【中文标题】查找每个员工的项目开始日期和结束日期(即开始日期和结束日期应该是连续的,在天/月/年中没有任何中断)【英文标题】:Find each employee Project Start Date and End Date (i.e., Start Date and End Date should be continuous without any break in Days/Months/Year) 【发布时间】:2022-01-18 12:30:06 【问题描述】:
ID EmployeeId ProjectId StartDate EndDate
1 1 100 01-04-2019 30-04-2019
2 1 100 01-05-2019 31-05-2019
3 1 100 01-12-2019 31-12-2019
4 1 100 01-01-2020 31-01-2020
5 2 200 01-01-2019 31-01-2019
6 2 200 01-02-2019 28-02-2019
7 2 200 01-04-2019 28-04-2019
8 2 200 01-05-2019 31-05-2019
9 2 200 01-06-2019 30-06-2019
10 3 100 01-08-2019 31-08-2019
11 3 100 01-09-2019 30-09-2019
12 3 200 01-10-2019 31-10-2019
13 3 200 01-11-2019 30-11-2019
14 3 300 01-12-2019 31-12-2019
15 3 300 01-01-2020 31-01-2020
16 3 300 01-02-2020 29-02-2020

预期输出

EmployeeId ProjectId StartDate EndDate
1 100 01-04-2019 31-05-2019
1 100 01-12-2019 31-01-2020
2 200 01-01-2019 28-02-2019
2 200 01-04-2019 28-04-2019
2 200 01-05-2019 30-06-2019
3 100 01-08-2019 30-09-2019
3 200 01-10-2019 30-11-2019
3 300 01-12-2019 29-02-2020

我试图找到当前行的结束日期是结束日期+1是下一行的开始日期,如果它是连续的,没有任何间隙,那么需要选择上一行的开始日期和当前行的结束日期。

;with MyCTE as

(

select mt.EmployeeId, mt.StartDate, mt.EndDate, ROW_NUMBER() over (order by ID) as RowNum

from #Employees mt

)

select c1.employeeId, case when c2.employeeId is null then c1.StartDate else dateadd(dd,1, c2.EndDate) end as StartDate,

c1.EndDate

from MyCTE c1
left  join MyCTE c2 
on C1.employeeId=c2.employeeId and
--and dateadd(dd,1,c1.startdate) 
c1.RowNum = c2.RowNum +1

【问题讨论】:

这听起来像是一个非常典型的间隙和孤岛问题。这种查询的例子有数百个,堆栈溢出,互联网上可能有数千个。 这是一篇特别好的文章,它对连续的日期进行分组,就像您在这里尝试做的那样。 sqlservercentral.com/articles/… 【参考方案1】:

这是一个典型的差距和孤岛问题。

有很多解决方案。一个典型的简单(如果不是很有效)的解决方案如下:

使用LAG 识别启动组/孤岛的行(根据需要进行分区) 使用带窗口的COUNT 为每个人分配一个组 ID 按该 ID 分组,并取值中的 MIN/MAX
WITH PrevValues AS (
    SELECT *,
      IsStart = CASE WHEN DATEADD(day, -1, StartDate) <=
                  LAG(EndDate) OVER (PARTITION BY EmployeeId, ProjectId ORDER BY StartDate)
                THEN NULL ELSE 1 END
    FROM Employees e
),
Groups AS (
    SELECT *,
      GroupId = COUNT(IsStart) OVER (PARTITION BY EmployeeId, ProjectId ORDER BY StartDate ROWS UNBOUNDED PRECEDING)
    FROM PrevValues pv
)
SELECT
  g.EmployeeId,
  g.ProjectId,
  StartDate = MIN(StartDate),
  EndDate = MAX(EndDate)
FROM Groups g
GROUP BY
  g.EmployeeId,
  g.ProjectId,
  g.GroupId;

db<>fiddle

【讨论】:

以上是关于查找每个员工的项目开始日期和结束日期(即开始日期和结束日期应该是连续的,在天/月/年中没有任何中断)的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQL:在由开始和结束定义的重叠日期范围内查找孤岛

开始日期和结束日期之间每个项目的 MS SQL Server QUERY SUM

Mysql 跨行查找日期范围

T-Sql 每年获取员工开始和结束日期

在包含多个开始和日期列表的表中查找日期,如果找到则返回默认值

从连续日期中查找最近的开始日期和结束日期