【问题标题】:T-SQL : calculate DateTime gapsT-SQL:计算日期时间间隔
【发布时间】:2020-04-11 08:54:39
【问题描述】:

代码:

DROP TABLE IF EXISTS #LookupDates ;

CREATE TABLE #LookupDates (StartDate DATETIME, EndDate DATETIME)

INSERT INTO #LookupDates
VALUES
    ( '2019-12-01 08:00:00', '2019-12-01 16:00:00' )
  , ( '2019-12-02 10:00:00', '2019-12-02 18:00:00' )
  , ( '2019-12-03 08:30:00', '2019-12-03 16:30:00' )
  , ( '2019-12-04 08:00:00', '2019-12-04 16:00:00' )
  , ( '2019-12-05 08:00:00', '2019-12-05 16:00:00' )
  , ( '2019-12-06 09:00:00', '2019-12-06 17:00:00' )
  , ( '2019-12-07 08:30:00', '2019-12-07 16:30:00' )
  , ( '2019-12-08 11:00:00', '2019-12-08 15:30:00' )
  , ( '2019-12-09 08:30:00', '2019-12-09 16:30:00' )
  , ( '2019-12-10 10:30:00', '2019-12-10 16:45:00' )

DROP TABLE IF EXISTS #Data ;

CREATE TABLE #Data (EmpId INT, ClockInDate DATETIME, ClockOutDate DATETIME)

INSERT INTO #Data
VALUES
    ( 1, '2019-12-01 07:00:00', '2019-12-01 07:30:00' ) -- Completely before
  , ( 1, '2019-12-01 18:00:00', '2019-12-01 22:00:00' ) -- Completely after
  , ( 1, '2019-12-02 09:30:00', '2019-12-02 18:00:00' ) -- Clockin before
  , ( 1, '2019-12-03 09:00:00', '2019-12-03 16:30:00' ) -- Clockin after
  , ( 1, '2019-12-04 08:00:00', '2019-12-04 15:45:00' ) -- Clockout before
  , ( 1, '2019-12-05 08:00:00', '2019-12-05 17:15:00' ) -- Clockout after
  , ( 1, '2019-12-06 08:40:00', '2019-12-06 16:45:00' ) -- Clockin before & Clockout before
  , ( 1, '2019-12-07 08:25:00', '2019-12-07 17:05:00' ) -- Clockin before & Clockout after
  , ( 1, '2019-12-08 12:00:00', '2019-12-08 15:15:00' ) -- Clockin after & Clockout before
  , ( 1, '2019-12-09 08:30:01', '2019-12-09 16:30:27' ) -- Clockin after & Clockout before
  , ( 1, '2019-12-10 10:30:00', '2019-12-10 16:45:00' ) -- Clockin on-time & Clockout on-time

描述:

LookupDates 包含公司的每日营业时间。实际表有额外天数的数据。

数据包含每个员工的时钟输入/输出时间戳。实际表有额外的 emps 和 days 数据。

目标:查找#Data 中的条目是否超出当天的营业时间。

  • 员工打卡早吗?多少秒?
  • 员工打卡迟到了吗?多少秒?
  • emp 提前下班了吗?多少秒?
  • emp 打卡晚了吗?多少秒?

期望的输出:

EmpId       LookupStartDate         ClockInDate             IsClockInBefore     ClockInBeforeTimeInSec      IsClockInAfter      ClockInAfterTimeInSec   LookupEndDate           ClockOutDate            IsClockOutBefore    ClockOutBeforeTimeInSec     IsClockOutAfter     ClockOutAfterTimeInSec
1           '2019-12-01 08:00:00'   '2019-12-01 07:00:00'   1                   3600                        0                   0                       '2019-12-01 16:00:00'   '2019-12-01 07:30:00'   1                   30600                       0                   0
1           '2019-12-01 08:00:00'   '2019-12-01 18:00:00'   0                   0                           1                   36000                   '2019-12-01 16:00:00'   '2019-12-01 22:00:00'   0                   0                           1                   21600
1           '2019-12-02 10:00:00'   '2019-12-02 09:30:00'   1                   1800                        0                   0                       '2019-12-02 18:00:00'   '2019-12-02 18:00:00'   0                   0                           0                   0
1           '2019-12-03 08:30:00'   '2019-12-03 09:00:00'   0                   0                           1                   1800                    '2019-12-03 16:30:00'   '2019-12-03 16:30:00'   0                   0                           0                   0
1           '2019-12-04 08:00:00'   '2019-12-04 08:00:00'   0                   0                           0                   0                       '2019-12-04 16:00:00'   '2019-12-04 15:45:00'   1                   900                         0                   0
1           '2019-12-05 08:00:00'   '2019-12-05 08:00:00'   0                   0                           0                   0                       '2019-12-05 16:00:00'   '2019-12-05 17:15:00'   0                   0                           1                   4500
1           '2019-12-06 09:00:00'   '2019-12-06 08:40:00'   1                   1200                        0                   0                       '2019-12-06 17:00:00'   '2019-12-06 16:45:00'   1                   900                         0                   0
1           '2019-12-07 08:30:00'   '2019-12-07 08:25:00'   1                   300                         0                   0                       '2019-12-07 16:30:00'   '2019-12-07 17:05:00'   0                   0                           1                   2100
1           '2019-12-08 11:00:00'   '2019-12-08 12:00:00'   0                   0                           1                   3600                    '2019-12-08 15:30:00'   '2019-12-08 15:15:00'   1                   900                         0                   0
1           '2019-12-09 08:30:00'   '2019-12-09 08:30:01'   0                   0                           1                   1                       '2019-12-09 16:30:00'   '2019-12-09 16:30:27'   0                   0                           1                   27
1           '2019-12-10 10:30:00'   '2019-12-10 10:30:00'   0                   0                           0                   0                       '2019-12-10 16:45:00'   '2019-12-10 16:45:00'   0                   0                           0                   0

【问题讨论】:

  • 因此您只需加入日期部分即可。例如,演员表上的内连接 b(a.LookupStartDate 作为日期)=演员表(b.ClockInDate 作为日期)?但我觉得这个“问题”可能比你描述的更多。
  • 很好地设置数据。做得好,谢谢。但是,缺少的是您解决问题的尝试,以及您遇到问题的指示。我们不是来为您编写代码的。我们随时为您解决遇到的问题提供帮助。
  • 您省略了您尝试的内容和一个问题。看起来您想加入date,计算重叠(如果有),然后使用case 表达式生成一些bit 列。

标签: sql sql-server tsql date sql-server-2016


【解决方案1】:
select
     #Data.EmpId
    ,#LookupDates.StartDate as LookupStartDate
    ,#Data.ClockInDate
    ,case when #Data.ClockInDate < #LookupDates.StartDate then 1 else 0 end as IsClockInBefore
    ,case when #Data.ClockInDate < #LookupDates.StartDate then datediff(second, #Data.ClockInDate, #LookupDates.StartDate) else 0 end as ClockInBeforeTimeInSec
    ,case when #Data.ClockInDate > #LookupDates.StartDate then 1 else 0 end as IsClockInAfter
    ,case when #Data.ClockInDate > #LookupDates.StartDate then datediff(second, #LookupDates.StartDate, #Data.ClockInDate) else 0 end as ClockInAfterTimeInSec
    ,#LookupDates.EndDate as LookupEndDate
    ,#Data.ClockOutDate
    ,case when #Data.ClockOutDate < #LookupDates.EndDate then 1 else 0 end as IsClockOutBefore
    ,case when #Data.ClockOutDate < #LookupDates.EndDate then datediff(second, #Data.ClockOutDate, #LookupDates.EndDate) else 0 end as ClockOutBeforeTimeInSec
    ,case when #Data.ClockOutDate > #LookupDates.EndDate then 1 else 0 end as IsClockOutAfter
    ,case when #Data.ClockOutDate > #LookupDates.EndDate then datediff(second, #LookupDates.EndDate, #Data.ClockOutDate) else 0 end as ClockOutAfterTimeInSec
from
    #LookupDates
    inner join
    #Data on cast(#LookupDates.StartDate as date) = cast(#Data.ClockInDate as date) --assuming the clock in is always the same date as the start date

【讨论】:

    【解决方案2】:

    假设查找日期和数据中的记录不分散在几天内,您可以在当天加入。剩下的只是一系列case 表达式和一些日期算术:

    select
        d.EmpId,
        d.StartDate,
        l.ClockInDate,
        case when d.StartDate < l.ClockInDate 
            then 1 
            else 0 
        end IsClockInBefore,
        case when d.StartDate < l.ClockInDate 
            then datediff(second, ClockInDate, StartDate) 
            else 0 
        end ClockInBeforeTimeInSec,
        case when d.StartDate > l.ClockInDate 
            then 1 
            else 0 
        end IsClockInAfter,
        case when d.StartDate > l.ClockInDate 
            then datediff(second, StartDate, ClockInDate) 
            else 0 
        end ClockInAfterTimeInSec,
        d.EndDate,
        l.ClockOutDate,
        case when d.EndDate < l.ClockOutDate 
            then 1 
            else 0 
        end IsClockOutBefore,
        case when d.EndDate < l.ClockOutDate 
            then datediff(second, ClockOutDate, StartDate) 
            else 0 
        end ClockOutBeforeTimeInSec,
        case when d.EndDate > l.ClockOutDate 
            then 1 
            else 0 
        end IsClockOutAfter,
        case when d.EndDate > l.ClockOutDate 
            then datediff(second, StartDate, ClockOutDate) 
            else 0 
        end ClockOutAfterTimeInSec
    from #Data d
    inner join #LookupDates l 
        on cast(d.ClockInDate as date) = cast(l.StartDate as date)
    

    【讨论】:

      【解决方案3】:

      不是不同的方法。
      只是尝试了一些不同的东西。
      (好吧,我承认。我真的很无聊。)

      SELECT
       io.EmpId,
       lk.StartDate AS LookupStartDate,
       io.ClockInDate,
       CAST(  IIF(io.ClockInDate < lk.StartDate,1,0) AS BIT) AS IsClockInBefore,
       (CASE WHEN io.ClockInDate < lk.StartDate
        THEN DATEDIFF(SECOND, io.ClockInDate, lk.StartDate) 
        ELSE 0 END) AS ClockInBeforeTimeInSec,
       CAST(  IIF(io.ClockInDate > lk.StartDate, 1, 0) AS BIT) AS IsClockInAfter,
       (CASE WHEN io.ClockInDate > lk.StartDate
        THEN DATEDIFF(SECOND, lk.StartDate, io.ClockInDate) 
        ELSE 0 END) AS ClockInAfterTimeInSec,
       lk.EndDate AS LookupEndDate,
       io.ClockOutDate,
       CAST(  IIF(io.ClockOutDate < lk.EndDate,1,0) AS BIT) AS IsClockOutBefore,
       (CASE WHEN io.ClockOutDate < lk.EndDate
        THEN DATEDIFF(SECOND, io.ClockOutDate, lk.EndDate) 
        ELSE 0 END) AS ClockOutBeforeTimeInSec,
       CAST(  IIF(io.ClockOutDate > lk.EndDate,1,0) AS BIT) AS IsClockOutAfter,
       (CASE WHEN io.ClockOutDate > lk.EndDate
        THEN DATEDIFF(SECOND, lk.EndDate, io.ClockOutDate) 
        ELSE 0 END) AS ClockOutAfterTimeInSec
      FROM #Data AS io
      JOIN #LookupDates AS lk
        ON CONVERT(DATE, lk.StartDate) = CONVERT(DATE, io.ClockInDate)
      ORDER BY io.EmpId, io.ClockInDate;
      GO
      
      员工 ID |查找开始日期 |时钟日期 | IsClockInBefore | ClockInBeforeTimeInSec | IsClockInAfter | ClockInAfterTimeInSec |查找结束日期 |时钟输出日期 | IsClockOutBefore | ClockOutBeforeTimeInSec | IsClockOutAfter | ClockOutAfterTimeInSec ----: | :----------------- | :----------------- | :---------------- | ---------------------: | :------------- | --------------------: | :----------------- | :----------------- | :--------------- | ----------------------: | :---------------- | ---------------------: 1 | 2019 年 1 月 12 日 08:00:00 | 2019 年 1 月 12 日 07:00:00 |真 | 3600 |假 | 0 | 2019 年 1 月 12 日 16:00:00 | 2019 年 1 月 12 日 07:30:00 |真 | 30600 |假 | 0 1 | 2019 年 1 月 12 日 08:00:00 | 2019 年 1 月 12 日 18:00:00 |假 | 0 |真 | 36000 | 2019 年 1 月 12 日 16:00:00 | 2019 年 1 月 12 日 22:00:00 |假 | 0 |真 | 21600 1 | 2019 年 2 月 12 日 10:00:00 | 2019 年 2 月 12 日 09:30:00 |真 | 1800 |假 | 0 | 2019 年 2 月 12 日 18:00:00 | 2019 年 2 月 12 日 18:00:00 |假 | 0 |假 | 0 1 | 2019 年 3 月 12 日 08:30:00 | 2019 年 3 月 12 日 09:00:00 |假 | 0 |真 | 1800 | 2019 年 3 月 12 日 16:30:00 | 2019 年 3 月 12 日 16:30:00 |假 | 0 |假 | 0 1 | 2019 年 4 月 12 日 08:00:00 | 2019 年 4 月 12 日 08:00:00 |假 | 0 |假 | 0 | 2019 年 4 月 12 日 16:00:00 | 2019 年 4 月 12 日 15:45:00 |真 | 900 |假 | 0 1 | 2019 年 5 月 12 日 08:00:00 | 2019 年 5 月 12 日 08:00:00 |假 | 0 |假 | 0 | 2019 年 5 月 12 日 16:00:00 | 2019 年 5 月 12 日 17:15:00 |假 | 0 |真 | 4500 1 | 2019 年 6 月 12 日 09:00:00 | 06/12/2019 08:40:00 |真 | 1200 |假 | 0 | 2019 年 6 月 12 日 17:00:00 | 2019 年 6 月 12 日 16:45:00 |真 | 900 |假 | 0 1 | 2019 年 7 月 12 日 08:30:00 | 2019 年 7 月 12 日 08:25:00 |真 | 300 |假 | 0 | 2019 年 7 月 12 日 16:30:00 | 2019 年 7 月 12 日 17:05:00 |假 | 0 |真 | 2100 1 | 2019 年 8 月 12 日 11:00:00 | 2019 年 8 月 12 日 12:00:00 |假 | 0 |真 | 3600 | 2019 年 8 月 12 日 15:30:00 | 2019 年 8 月 12 日 15:15:00 |真 | 900 |假 | 0 1 | 2019 年 9 月 12 日 08:30:00 | 2019 年 9 月 12 日 08:30:01 |假 | 0 |真 | 1 | 2019 年 9 月 12 日 16:30:00 | 2019 年 9 月 12 日 16:30:27 |假 | 0 |真 | 27 1 | 2019 年 10 月 12 日 10:30:00 | 2019 年 10 月 12 日 10:30:00 |假 | 0 |假 | 0 | 2019 年 10 月 12 日 16:45:00 | 2019 年 10 月 12 日 16:45:00 |假 | 0 |假 | 0

      db小提琴here

      【讨论】:

        【解决方案4】:

        我想您需要的只是针对不同列数的多个相同案例。您的查询中没有其他内容。

             Select case when 
            checkindatetime<estimated then
            1 else 0 end as "CheckedInearly" ,
            Abs(checkindatetime-estimated) 
           .....same logic for other columns
           From table
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多