查找每个员工的项目开始日期和结束日期(即开始日期和结束日期应该是连续的,在天/月/年中没有任何中断)
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
【讨论】:
以上是关于查找每个员工的项目开始日期和结束日期(即开始日期和结束日期应该是连续的,在天/月/年中没有任何中断)的主要内容,如果未能解决你的问题,请参考以下文章
开始日期和结束日期之间每个项目的 MS SQL Server QUERY SUM