我有以下两个表
人
.box
班次
margin: 8px 0 0 -11px;
这意味着,例如,凯特(Kate)的工作时间为20180101至20181231。在这段时间里,她将在天鹅站(Swan)工作,时间为20180101至20180131,箭头工作地点为箭头(Arrow),工作时间为20180301至20180331,工作时间为20180401至20181231。 >
我的目标是进入下表
+--------+---------------+-------------+
| Name | ContractStart | ContractEnd |
+--------+---------------+-------------+
| Kate | 20180101 | 20181231 |
| Sawyer | 20180101 | 20181231 |
| Ben | 20170601 | 20181231 |
+--------+---------------+-------------+
这意味着Kate在20180201至20180228之间免费。
我的第一个想法是创建一个表,其中包含2017年和2018年的每一天,假设一个+---------+--------+------------+----------+
| Station | Name | ShiftStart | ShiftEnd |
+---------+--------+------------+----------+
| Swan | Kate | 20180101 | 20180131 |
| Arrow | Kate | 20180301 | 20180331 |
| Arrow | Kate | 20180401 | 20181231 |
| Flame | Sawyer | 20180101 | 20181231 |
| Swan | Ben | 20180101 | 20181231 |
+---------+--------+------------+----------+
,然后使用+------+---------------+-------------+
| | VacationStart | VacationEnd |
+------+---------------+-------------+
| Kate | 20180201 | 20180228 |
| Ben | 20170601 | 20171231 |
+------+---------------+-------------+
JOIN 加入该表以查找每一天每个人都应该有空。此时,再次用CalTable
联接结果表,以证明日期为People
。
考虑到我拥有将近1.000.000的人,并且通常在Shifts
和NOT BETWEEN ShiftStart AND ShiftEnd
之间,这些步骤会给我带来正确的结果,但速度却很慢。这是10到20岁。
以更聪明,更快捷的方式获得结果的正确方法是什么?
谢谢。 This is the data of the example on db<>Fiddle
对于@ A_Name_Does_Not_Matter,这是我的尝试
ContractStart
然后汇总日期this query。
答案 0 :(得分:1)
因此,某人的开始日期可能是休假的开始,您可以通过使用CROSS APPLY来获得TOP 1班次,从而找到他们的第一个班次(负1天)的日期来找到休假的结束截止日期
在他们没有轮班的异常情况下,假期将在合同结束日期结束。
将来的假期然后在轮班后的第二天开始,并在下一个轮班的前一天结束(可以通过OUTER APPLY找到),如果没有进一步的轮班,则默认为合同约定的结束日期
SELECT p.name, p.contractStart vacationstart, p.ContractEnd vacationend from people p WHERE not exists(select 1 from shifts s where p.name = s.name)
UNION
SELECT p2.name,
p2.contractStart vacationstart,
dateadd(day,-1,DQ.ShiftStart) as vacationend
from PEOPLE P2
CROSS APPLY
(SELECT TOP 1 s2.ShiftStart FROM shifts s2 WHERE p2.name = s2.name order by sfiftstart) DQ
WHERE DQ.ShiftStart > p2.contractstart
UNION
select P3.NAME,
dateadd(day,1,s3.ShiftEnd) vacationstart,
COALESCE(dateadd(day,-1, DQ2.shiftStart),P3.ContractEnd) --you might have to add handling yourself for removing a case where they work on their contract end date
FROM people p3 JOIN shifts s3 on p3.name = s3.name
OUTER APPLY (SELECT TOP 1 s4.shiftStart
from shifts s4
where s4.name = p3.name
and
s4.shiftstart > s3.shiftstart
order by s4.shiftstart) DQ2
没有测试数据对我来说很难验证。 对于员工来说,我追求的是。
合同开始,Shift1开始-1
Shift1End + 1,Shift2Start-1
Shift2End + 1,Shift3Start-1
Shift3End + 1,ContractEnd
然后添加“不转移”的情况 最后,移位可能是连续的,导致休假的持续时间为零或更少-您可以通过将查询设为子查询并进行简单过滤来过滤这些