sql - 计算夜类时间

标签 sql sql-server sql-server-2008 t-sql

我正在计算 Night_Start_Time、Night_Shift_End、Night_Shift_Duration

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

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

例如;

  • 03:00 pm - 22:29 pm,在这种情况下,员工仅工作 29 分钟,其中 少于30分钟,不属于夜类
  • 03:00 pm -- 22:30 pm 这是夜类,因为该员工工作了 30 分钟。
  • 上午 05:29 - 下午 2:00,员工工作了 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

最佳答案

请尝试以下代码...

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

此段提取 Shift_StartTIME 组件并测试它是否超出夜类时间范围。如果是,那么它会提取 Shift_StartDATE 组件并将其转换为字符串,以便可以将日期与夜类开始时间的字符串表示形式连接起来。然后,连接的字符串将转换为其等效的 DATETIME 值。

如果 Shift_StartTIME 部分未落在夜类时间范围之外,则返回 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 分钟以秒表示,允许以秒为单位的精确度)<在该记录识别的夜类开始时间之后,该记录的 Night_Start_TimeNight_Shift_End 字段将设置为其各自的夜类时间,并且Night_Shift_Duration 设置为它们之间的小时差,计算方式为秒差除以一小时内的秒数。

我已经针对使用您提供的脚本创建的数据库测试了我的语句(谢谢您),并达到了预期的结果。

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

附录1

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

INSERT INTO #Shift
VALUES ( 7,
         '20170522 05:31:00',
         '20170522 22:01:00' ),
       ( 8,
         '20170522 04:31:00',
         '20170522 22:01:00' );

附录2

以下语句是上述语句的变体,它使用子查询来确定每个记录的 Night_Start_TimeNight_Shift_End 值,没有考虑两者之间的差异。主查询使用如此生成的值来确定 Night_Start_TimeNight_Shift_EndNight_Shift_Duration 的最终值。

我不确定哪个更有效。

SELECT Eid,
       Shift_Start,
       Shift_End,
       CASE
           WHEN DATEDIFF( S,
                          Night_Start_Time,
                          Night_Shift_End
                        ) >= 1800 THEN
               Night_Start_Time
           ELSE
               NULL
       END AS Night_Start_Time,
       CASE
           WHEN DATEDIFF( S,
                          Night_Start_Time,
                          Night_Shift_End
                        ) >= 1800 THEN
               Night_Shift_End
           ELSE
               NULL
       END AS Night_Shift_End,
       CASE
           WHEN DATEDIFF( S,
                          Night_Start_Time,
                          Night_Shift_End
                        ) >= 1800 THEN
               DATEDIFF( S,
                          Night_Start_Time,
                          Night_Shift_End
                       ) / 3600.0
           ELSE
               0.0
       END AS Night_Shift_Duration
FROM ( SELECT Eid,
              Shift_Start,
              Shift_End,
              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 Night_Start_Time,
              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 Night_Shift_End
       FROM #Shift
     ) AS shiftTimesFinder;

关于sql - 计算夜类时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44125934/

相关文章:

sql - 是否可以将 DDL 更改包装在 PostgreSQL 的事务中?

sql - Foreach 循环文件名

c# - 将带有子查询的sql查询转换为linq语句

sql - 消息 8114,级别 16,状态 5,第 1 行将数据类型 varchar 转换为数字时出错

sql-server - 如果十分之三的列在 sql server 中没有返回 null,则应在另一列中返回特定值

sql - 获取有条件的数据

sql-server - SQL Server 2008 : Why table scaning when another logical condition is satisfied first?

c# - Linq To Sql - 如何获取插入记录的数量

sql - 有效地选择数据sql

c# - ORA-12545 : Connect failed because target host or object does not exist - No error on System. Data.OracleClient