计算夜班持续时间

时间:2017-05-23 04:40:16

标签: sql sql-server sql-server-2008 tsql

我想要计算Night_Start_Time,Night_Shift_End,Night_Shift_Duration

我们定义了Night_Shift_Start_Time = 22:00 hrs和Night_Shift_End_Time = 06:00 hrs。

要获得夜班资格,员工应该至少工作30分钟,否则不会被视为夜班

例如;

  • 03:00 pm - 22:29 pm,在这种情况下,员工只工作29分钟 不到30分钟它不会在夜班下来
  • 03:00 pm - 22:30 pm这是员工30岁时的夜班 分钟。
  • 05:29 am - 2:00 pm,员工工作31分钟(06:00 - 05:29) 它带有夜班
  • 上午05:31 - 下午2:00,因为该员工工作了29分钟的夜班 持续时间它不能视为夜班。

CREATE TABLE #Shift 
  (Eid int,
   Shift_Start datetime,
   Shift_End datetime);
GO

INSERT INTO #Shift
VALUES
  (1,'20170522 20:00:00.000','20170523 06:00:00.000'),
  (2,'20170522 02:00:00.000','20170522 12:00:00.000'),
  (3,'20170522 23:00:00.000','20170523 08:00:00.000'),
  (4,'20170522 23:00:00.000','20170523 00:00:00.000'),
  (5,'20170522 00:00:00.000','20170522 05:00:00.000'),
  (6,'20170522 15:00:00.000','20170522 21:00:00.000');
GO

预期输出

Eid  Shift_Start              Shift_End                Night_Start_Time         Night_Shift_End          Night_Shift_Duration
1    2017-05-22 20:00:00.000  2017-05-23 06:00:00.000  2017-05-22 22:00:00.000  2017-05-23 06:00:00.000  8
2    2017-05-22 02:00:00.000  2017-05-22 12:00:00.000  2017-05-22 02:00:00.000  2017-05-22 06:00:00.000  4
3    2017-05-22 23:00:00.000  2017-05-23 08:00:00.000  2017-05-22 23:00:00.000  2017-05-23 06:00:00.000  7
4    2017-05-22 23:00:00.000  2017-05-23 00:00:00.000  2017-05-22 23:00:00.000  2017-05-23 00:00:00.000  1
5    2017-05-22 00:00:00.000  2017-05-22 05:00:00.000  2017-05-22 00:00:00.000  2017-05-22 05:00:00.000  5
6    2017-05-22 15:00:00.000  2017-05-22 21:00:00.000  NULL                     NULL                     0

3 个答案:

答案 0 :(得分:2)

请尝试以下代码......

SELECT Eid,
       Shift_Start,
       Shift_End,
       CASE
           WHEN DATEDIFF( S,
                          CASE
                              WHEN CAST( Shift_Start AS TIME ) BETWEEN '05:30:01' AND '22:00:00' THEN
                                  CAST( ( CAST( CAST( Shift_Start AS DATE ) AS VARCHAR ) + ' 22:00' ) AS DATETIME )
                              ELSE
                                  Shift_Start
                          END,
                          CASE
                              WHEN CAST( Shift_End AS TIME ) BETWEEN '06:00:01' AND '22:29:59' THEN
                                  CAST( ( CAST( CAST( Shift_End AS DATE ) AS VARCHAR ) + ' 06:00' ) AS DATETIME )
                              ELSE
                                  Shift_End
                          END
                        ) >= 1800 THEN
               CASE
                   WHEN CAST( Shift_Start AS TIME ) BETWEEN '05:30:01' AND '22:00:00' THEN
                       CAST( ( CAST( CAST( Shift_Start AS DATE ) AS VARCHAR ) + ' 22:00' ) AS DATETIME )
                   ELSE
                       Shift_Start
               END
           ELSE
               NULL
       END AS Night_Start_Time,
       CASE
           WHEN DATEDIFF( S,
                          CASE
                              WHEN CAST( Shift_Start AS TIME ) BETWEEN '05:30:01' AND '22:00:00' THEN
                                  CAST( ( CAST( CAST( Shift_Start AS DATE ) AS VARCHAR ) + ' 22:00' ) AS DATETIME )
                              ELSE
                                  Shift_Start
                          END,
                          CASE
                              WHEN CAST( Shift_End AS TIME ) BETWEEN '06:00:01' AND '22:29:59' THEN
                                  CAST( ( CAST( CAST( Shift_End AS DATE ) AS VARCHAR ) + ' 06:00' ) AS DATETIME )
                              ELSE
                                  Shift_End
                          END
                        ) >= 1800 THEN
               CASE
                   WHEN CAST( Shift_End AS TIME ) BETWEEN '06:00:01' AND '22:29:59' THEN
                       CAST( ( CAST( CAST( Shift_End AS DATE ) AS VARCHAR ) + ' 06:00' ) AS DATETIME )
                   ELSE
                       Shift_End
               END
           ELSE
               NULL
       END AS Night_Shift_End,
       CASE
           WHEN DATEDIFF( S,
                          CASE
                              WHEN CAST( Shift_Start AS TIME ) BETWEEN '05:30:01' AND '22:00:00' THEN
                                  CAST( ( CAST( CAST( Shift_Start AS DATE ) AS VARCHAR ) + ' 22:00' ) AS DATETIME )
                              ELSE
                                  Shift_Start
                          END,
                          CASE
                              WHEN CAST( Shift_End AS TIME ) BETWEEN '06:00:01' AND '22:29:59' THEN
                                  CAST( ( CAST( CAST( Shift_End AS DATE ) AS VARCHAR ) + ' 06:00' ) AS DATETIME )
                              ELSE
                                  Shift_End
                          END
                        ) >= 1800 THEN
               DATEDIFF( S,
                          CASE
                              WHEN CAST( Shift_Start AS TIME ) BETWEEN '05:30:01' AND '22:00:00' THEN
                                  CAST( ( CAST( CAST( Shift_Start AS DATE ) AS VARCHAR ) + ' 22:00' ) AS DATETIME )
                              ELSE
                                  Shift_Start
                          END,
                          CASE
                              WHEN CAST( Shift_End AS TIME ) BETWEEN '06:00:01' AND '22:29:59' THEN
                                  CAST( ( CAST( CAST( Shift_End AS DATE ) AS VARCHAR ) + ' 06:00' ) AS DATETIME )
                              ELSE
                                  Shift_End
                          END
                        ) / 3600.0
           ELSE
               0.0
       END AS Night_Shift_Duration
FROM #Shift;

本声明首先使用以下段来选择夜班开始时间(而不是班次开始时间)......

CASE
    WHEN CAST( Shift_Start AS TIME ) BETWEEN '05:30:01' AND '22:00:00' THEN
        CAST( ( CAST( CAST( Shift_Start AS DATE ) AS VARCHAR ) + ' 22:00' ) AS DATETIME )
    ELSE
        Shift_Start
END

此段提取TIME的{​​{1}}组件,并测试它是否超出夜班时间范围。如果是,则它提取Shift_Start的{​​{1}}组件并将其转换为字符串,以便它可以将日期与夜班开始时间的字符串表示连接起来。然后将连接的字符串转换为等效的DATE值。

如果Shift_Start的{​​{1}}分量不在夜班时间范围之外,则会返回DATETIME的值。

以下陈述使用类似的逻辑来确定夜班结束时间......

TIME

如果记录的夜班结束时间超过Shift_Start秒(Shift_Start分钟表示为秒,则允许第二级的精度级别 >确定该记录的夜班开始时间,然后该记录的字段CASE WHEN CAST( Shift_End AS TIME ) BETWEEN '05:30:01' AND '22:00:00' THEN CAST( ( CAST( CAST( Shift_End AS DATE ) AS VARCHAR ) + ' 06:00' ) AS DATETIME ) ELSE Shift_End END 1800将设置为各自的夜班时间,30设置为它们之间的差异小时数,以秒为单位的差值除以一小时内的秒数计算。

我已经针对使用您提供的脚本创建的数据库测试了我的声明(谢谢你),并且实现了预期的结果。

如果您有任何问题或意见,请随时发表评论。

附录1

针对示例数据库运行以下语句以允许进一步测试...

Night_Start_Time

附录2

以下语句是上述语句的变体,它使用子查询为每条记录确定Night_Shift_EndNight_Shift_Duration的值,而不用考虑它们之间的差异二。主查询使用如此生成的值来确定INSERT INTO #Shift VALUES ( 7, '20170522 05:31:00', '20170522 22:01:00' ), ( 8, '20170522 04:31:00', '20170522 22:01:00' ); Night_Start_TimeNight_Shift_End的最终值。

我不确定哪个更有效率。

Night_Start_Time

答案 1 :(得分:-1)

;WITH CTE
AS
(
    SELECT *,
           CASE
               WHEN DATEPART( HH, Shift_Start ) >= 22 OR DATEPART( HH, Shift_Start ) <= 6 THEN
                   IIF( DATEPART( HH, Shift_Start ) > 6, 6 + ( DATEPART( HH, Shift_Start ) - 22 ), ( 6 - DATEPART( HH, Shift_Start ) ) )
           END Night_Shift_StartTrue,
           CASE
               WHEN DATEPART( HH, Shift_End ) >= 22 OR DATEPART( HH, Shift_End ) <= 6 THEN
                   IIF( DATEPART( HH, Shift_End ) > 6, ( DATEPART( HH, Shift_End ) - 22 ), ( DATEPART( HH, Shift_End ) + 2 ) )
           END Night_Shift_EndTrue
    FROM #shift
)
SELECT Eid,
       Shift_Start,
       Shift_End,
       CASE
           WHEN ISNULL( Night_Shift_StartTrue, 0 ) > 30 OR ISNULL( Night_Shift_EndTrue, 0 ) > 30 THEN
               IIF( ISNULL( Night_Shift_StartTrue, 0 ) > 0, Shift_Start, DATEADD( HOUR, 22, CAST( CAST( Shift_End AS DATE ) AS DATETIME ) ) )
       END Night_Start_Time,
       CASE
           WHEN ISNULL( Night_Shift_StartTrue, 0 ) > 30 OR ISNULL( Night_Shift_EndTrue, 0 ) > 30 THEN
               IIF( ISNULL( Night_Shift_EndTrue, 0 ) > 0, Shift_End, DATEADD( HOUR, 6, CAST( CAST( Shift_Start AS DATE ) AS DATETIME ) ) )
       END Night_End_Time,
       CONCAT( ISNULL( ( Night_Shift_StartTrue / 60 ), 0 ), ' hr ', Night_Shift_StartTrue % 60, ' mins' ) Night_Shift_StartTrue,
       CONCAT( ISNULL( ( Night_Shift_EndTrue / 60), 0 ), ' hr ', Night_Shift_EndTrue % 60, ' mins' ) Night_Shift_EndTrue
FROM CTE

第四和第五次入场有开始和结束时间的夜班时间,根据您的期望选择合适的时间。

答案 2 :(得分:-1)

试试这段代码。请注意每个WHERE中的SELECT条件,以了解您的不同情况。

同样,您可以自行更正并让我知道此代码无效的样本数据。

CREATE TABLE #Shift 
    ( Eid           INT,
      Shift_Start   DATETIME,
      Shift_End     DATETIME );
GO

INSERT INTO #Shift
VALUES
    ( 1, '20170522 20:00:00.000', '20170523 06:00:00.000' ),
    ( 2, '20170522 5:31:00.000', '20170522 12:00:00.000' ),
    ( 3, '20170522 23:00:00.000', '20170523 08:00:00.000' ),
    ( 4, '20170522 23:00:00.000', '20170523 00:00:00.000' ),
    ( 5, '20170522 05:29:00.000', '20170522 14:00:00.000' ),
    ( 6, '20170522 15:00:00.000', '20170522 22:30:00.000' );
GO

DECLARE @Night_Shift_Start_Time TIME = '22:00 PM' 
DECLARE @Night_Shift_Start_Time1 TIME = '12:00 AM' 
DECLARE @Night_Shift_End_Time TIME = '06:00 AM'

SELECT * FROM #Shift
WHERE CAST( Shift_Start AS TIME ) >= @Night_Shift_Start_Time
AND CAST( Shift_End AS TIME ) <= @Night_Shift_End_Time
AND  DATEDIFF( MINUTE, Shift_Start, Shift_End ) >= 30
UNION ALL

SELECT * FROM #Shift
WHERE CAST( Shift_End AS TIME ) >= @Night_Shift_Start_Time
  AND DATEDIFF( MINUTE, @Night_Shift_Start_Time, Shift_End ) >= 30

UNION ALL

SELECT * FROM #Shift
WHERE CAST( Shift_Start AS TIME ) <= @Night_Shift_End_Time
  AND DATEDIFF( MINUTE, CAST( Shift_Start AS TIME ), @Night_Shift_End_Time ) >= 30

DROP TABLE #Shift