查找未发现的时期而不分解每个组合

时间:2018-12-13 11:11:50

标签: sql sql-server datetime sql-server-2005 period

我有以下两个表

.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的人,并且通常在ShiftsNOT BETWEEN ShiftStart AND ShiftEnd之间,这些步骤会给我带来正确的结果,但速度却很慢。这是10到20岁。

以更聪明,更快捷的方式获得结果的正确方法是什么?

谢谢。 This is the data of the example on db<>Fiddle


对于@ A_Name_Does_Not_Matter,这是我的尝试

ContractStart

然后汇总日期this query

1 个答案:

答案 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

然后添加“不转移”的情况 最后,移位可能是连续的,导致休假的持续时间为零或更少-您可以通过将查询设为子查询并进行简单过滤来过滤这些