制作滚动的4 on / 4off班次日历

时间:2016-06-27 20:36:25

标签: sql-server date dynamic calendar

希望为两班制(蓝队/红队)的员工模型生成一个动态日历,这些日历为4天/ 4天。我希望能够根据静态日期捕获未来日期和过去日期。

例如,如果Blue团队的第一天是2016年6月1日,最后一天是2016年6月4日,那么Red团队的第一天就是2016年6月5日和最后一天是2016年6月8日,我如何创建一个在SQL Server中向前和向后看的滚动视图?

基本上我想知道哪一支队伍应该在某一天工作,这将允许我计算人员配置百分比,以查看谁出去度假/生病等。如果我可以建立滚动日历视图,我可以将其用作衡量员工绩效的驱动因素。

理想情况下,我想动态生成此视图:

  • 蓝队静态班次开始日期 - 6/1/2016 06:00:00 AM
  • 红队静态班次开始日期 - 2016年6月5日06:00:00

示例输出:

Shift | Date
Blue  | 5/24/2016 06:00:00 AM
Blue  | 5/25/2016 06:00:00 AM
Blue  | 5/26/2016 06:00:00 AM
Blue  | 5/27/2016 06:00:00 AM
Red   | 5/28/2016 06:00:00 AM
Red   | 5/29/2016 06:00:00 AM
Red   | 5/30/2016 06:00:00 AM
Red   | 5/31/2016 06:00:00 AM
Blue  | 6/1/2016 06:00:00 AM
Blue  | 6/2/2016 06:00:00 AM
Blue  | 6/3/2016 06:00:00 AM
Blue  | 6/4/2016 06:00:00 AM
Red   | 6/5/2016 06:00:00 AM
Red   | 6/6/2016 06:00:00 AM
Red   | 6/7/2016 06:00:00 AM
Red   | 6/8/2016 06:00:00 AM
Blue  | 6/9/2016 06:00:00 AM
Blue  | 6/10/2016 06:00:00 AM
Blue  | 6/11/2016 06:00:00 AM
Blue  | 6/12/2016 06:00:00 AM
Red   | etc...

提前感谢任何建议。

更新

利用link的代码

我能够制作出滚动的未来日期:

; with samples as  
(
    -- start with 6/1/2016
    select cast( '06-01-2016 06:00' as datetime ) as sample
    union all
    -- add days up to the desired end date 
    select dateadd( day, 1, sample )
    from samples
    where sample <= '2020-12-31'
),
extendedsamples as  
(
    -- calculate the number of days since the beginning of the first shift on 6/1/2016.
    select 
        sample, datediff( day, '06-01-2016 06:00', sample ) as days
    from samples 
),
shifts as 
(
    -- calculate the shifts for each day.
    select 
        *,
        case when ( days + 1 ) % 8 between 1 and 4 then 'Blue' else 'Red' end as shifts
    from extendedsamples
)
select
    shifts,
    sample
from 
    shifts
option (maxrecursion 0)

我现在需要弄清楚如何为这段代码制作历史作品,以便我可以捕捉以前的人员编制百分比......

更新2:

所以看起来如果我只是将一些函数和数字反转并默认为Blue team的静态转换6/1/2016前一天。我也能够产生历史性的观点。

; with samples as 
(
     -- start with 5/31/2016 to pull historical.
     select cast( '05-31-2016 06:00' as datetime ) as sample
     union all
     -- subtract days back to the desired start date.
     select dateadd( day, -1, sample )
     from samples
     where sample >= '2015-01-01'
),
extendedsamples as 
(
     -- calculate the number of days before the beginning of the first blue shift on 6/1/2016.
     select sample, datediff( day, '05-31-2016 06:00', sample ) as days
     from samples 
),     
shifts as 
(
    -- calculate the shifts for each day.
    select 
        *,
        case when ( days - 1 ) % 8 between -4 and -1 then 'Red' else 'Blue' end as shifts
    from extendedsamples 
)
select  
    shifts,
    sample
from 
    shifts
option (maxrecursion 0)

我现在可以将这些结果转储到静态表中以供参考。有更好的解决方法吗?如果没有,我会继续这样做,并将此问题标记为已回答。

2 个答案:

答案 0 :(得分:0)

;WITH cteDates AS (
    --put in your desired start date
    SELECT CAST('5/1/2016 06:00:00 AM' AS DATETIME) AS StartDate

    UNION ALL

    SELECT
       StartDate + 1 AS StartDate
    FROM
       cteDates
    WHERE
       StartDate + 1 <= '6/30/2016 06:00:00 AM'
       --put in your desired end date
)

SELECT
    *
    ,CASE
       --just use the beginning day of your known blue shift
       WHEN DATEDIFF(day,'6/1/2016 06:00:00 AM',StartDate) % 8 BETWEEN -4 AND -1 THEN 'Red'
       WHEN StartDate <= '6/1/2016 06:00:00 AM' THEN 'Blue'
       WHEN (ABS(DATEDIFF(day,'6/1/2016 06:00:00 AM',StartDate)) + 1) % 8 BETWEEN 1 AND 4 THEN 'Blue'
       ELSE 'Red'
    END AS TeamShift
FROM
    cteDates d

在另一个答案中,Row_Number可能有一些方法,但您需要知道该类型方法最早工作时的起始班次。但是,您可以使用递归cte轻松生成自己的日期表,然后将已经使用的公式调整为case语句。诀窍在于,在2016年6月6日向前计数时,您需要第1天到第4天蓝色但向后计数-4到-1将是红色,因此您必须考虑使用案例陈述的逻辑转换。这也是row_number下降区域之一。

答案 1 :(得分:0)

@Matt指出我错过了一个主要要求。在UDF的帮助下生成动态日期范围(下面列出)和“锚定日期”,方法并不是那么糟糕。

  

我已经测试了未来和过去的随机日期,结果似乎有效   真。

Declare @StartDate  DateTime = '2016-07-15 06:00:00'
Declare @EndDate    DateTime = '2017-12-31 06:00:00'
Declare @AnchorDate DateTime = '2016-06-01 06:00:00'

;with cteBasePos as (Select Date  = RetVal,NegRowNr=0,PosRowNr =  Row_Number() over (Order By RetVal Asc ) From  [dbo].[udf-Create-Range-Date](@AnchorDate,@EndDate   ,'DD',1) Where @EndDate  >@AnchorDate)
     ,cteBaseNeg as (Select Date  = RetVal,NegRowNr =  Row_Number() over (Order By RetVal Desc)-1,PosRowNr=0 From  [dbo].[udf-Create-Range-Date](@StartDate ,@AnchorDate,'DD',1) Where @StartDate<@AnchorDate)
     Select Date
           ,Shift = IIF(((RowNr-1)/4) % 2 = 0 ,'Blue','Red')
     From (
             Select Date,RowNr=NegRowNr+4 from cteBaseNeg Where NegRowNr>0
             Union All
             Select Date,RowNr=PosRowNr+0 from cteBasePos
          ) A
     Where Date Between @StartDate and DateAdd(DD,1,@EndDate)
     Order By Date

返回

Date                    Shift
2016-05-22 06:00:00.000 Red
2016-05-23 06:00:00.000 Red
2016-05-24 06:00:00.000 Blue
2016-05-25 06:00:00.000 Blue
2016-05-26 06:00:00.000 Blue
2016-05-27 06:00:00.000 Blue
2016-05-28 06:00:00.000 Red
2016-05-29 06:00:00.000 Red
2016-05-30 06:00:00.000 Red
2016-05-31 06:00:00.000 Red
2016-06-01 06:00:00.000 Blue   -- Anchor Date
2016-06-02 06:00:00.000 Blue
2016-06-03 06:00:00.000 Blue
2016-06-04 06:00:00.000 Blue
2016-06-05 06:00:00.000 Red
2016-06-06 06:00:00.000 Red
2016-06-07 06:00:00.000 Red
2016-06-08 06:00:00.000 Red
2016-06-09 06:00:00.000 Blue
2016-06-10 06:00:00.000 Blue
2016-06-11 06:00:00.000 Blue
2016-06-12 06:00:00.000 Blue
2016-06-13 06:00:00.000 Red
2016-06-14 06:00:00.000 Red
2016-06-15 06:00:00.000 Red
2016-06-16 06:00:00.000 Red
2016-06-17 06:00:00.000 Blue
2016-06-18 06:00:00.000 Blue
2016-06-19 06:00:00.000 Blue
2016-06-20 06:00:00.000 Blue
2016-06-21 06:00:00.000 Red
2016-06-22 06:00:00.000 Red
2016-06-23 06:00:00.000 Red
2016-06-24 06:00:00.000 Red
2016-06-25 06:00:00.000 Blue
2016-06-26 06:00:00.000 Blue
2016-06-27 06:00:00.000 Blue
2016-06-28 06:00:00.000 Blue
2016-06-29 06:00:00.000 Red
2016-06-30 06:00:00.000 Red

UDF:

CREATE FUNCTION [dbo].[udf-Create-Range-Date] (@DateFrom datetime,@DateTo datetime,@DatePart varchar(10),@Incr int)

Returns 
@ReturnVal Table (RetVal datetime)

As
Begin
    With DateTable As (
        Select DateFrom = @DateFrom
        Union All
        Select Case @DatePart
               When 'YY' then DateAdd(YY, @Incr, df.dateFrom)
               When 'QQ' then DateAdd(QQ, @Incr, df.dateFrom)
               When 'MM' then DateAdd(MM, @Incr, df.dateFrom)
               When 'WK' then DateAdd(WK, @Incr, df.dateFrom)
               When 'DD' then DateAdd(DD, @Incr, df.dateFrom)
               When 'HH' then DateAdd(HH, @Incr, df.dateFrom)
               When 'MI' then DateAdd(MI, @Incr, df.dateFrom)
               When 'SS' then DateAdd(SS, @Incr, df.dateFrom)
               End
        From DateTable DF
        Where DF.DateFrom < @DateTo
    )

    Insert into @ReturnVal(RetVal) Select DateFrom From DateTable option (maxrecursion 32767)

    Return
End

-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2020-10-01','YY',1) 
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2020-10-01','DD',1) 
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2016-10-31','MI',15) 
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2016-10-02','SS',1)