【问题标题】:Produce a rolling 4 on/4off shift calendar生成滚动 4 on/4off 班次日历
【发布时间】:2016-10-29 23:43:52
【问题描述】:

希望为两班(蓝队/红队)的人员配备模型生成一个动态日历,即 4 天上班/4 天休息。我希望能够根据静态日期捕获未来的日期和过去的日期。

例如,如果蓝队的第一天轮班是 2016 年 6 月 1 日,最后一天是 6/4/2016,而红队的第一天轮班是 2016 年 6 月 5 日,最后一天现在是 6/8/2016,如何在 SQL Server 中创建向前和向后的滚动视图?

基本上我想知道在特定的一天应该为哪个团队配备人员,这将允许我计算人员配备百分比以查看谁休假/生病/等。如果我可以构建滚动日历视图,我可以将其用作衡量员工绩效的驱动因素。

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

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

样本输出:

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:

所以看起来如果我只是反转一些函数和数字并默认为蓝队 2016 年 6 月 1 日静态班次的前一天。我也可以生成历史视图。

; 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)

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

【问题讨论】:

    标签: sql-server date dynamic calendar


    【解决方案1】:

    @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) 
    

    【讨论】:

    • 谢谢约翰。您的解决方案以及@Matt 的解决方案无疑为我提供了一些可供考虑的选择。看看 UDF 方法,如果我需要比较日期,例如从工作订单表中,这可能会满足根据工作订单日期确定哪个班次正在工作,对吗?
    • UDF 仅用于动态日期范围,我一直将它用于无数应用程序。 cte,也可以是 UDF,可以回答谁在什么日期工作的问题
    【解决方案2】:
    ;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 月 1 日第 0 天向前计数时,您希望第 1 天到第 4 天是蓝色的,但向后计数 -4 到 -1 会是红色的,因此您必须使用案例语句来解释逻辑上的变化。这也是 row_number 分解的领域之一。

    【讨论】:

    • 谢谢马特。感谢您的回复和解决方案。它像冠军一样工作,@John 也是如此。我可以通过多种方式应用这些方法,现在我必须找出最佳途径。为澄清起见,您能解释一下 %8 在您的 Case 语法中的作用吗?
    • % 是除法的余数。所以 7/8 给你 7 的余数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-04
    • 1970-01-01
    • 2018-11-03
    • 1970-01-01
    相关资源
    最近更新 更多