SQL计算两个DateTime值之间的DayTime和NightTime

时间:2016-04-20 10:59:09

标签: sql sql-server

我遇到了SQL问题。我有一个查询,它创建一个临时表,用其他几个表中的数据填充它,进行一些计算和更新,并将这些数据提供给应用程序。最后一步是计算两个日期时间之间的小时数和分钟数,但它们应分为dayHours,dayMins,nightHours,nightMins(日期时间可以是20天以上)。以下要点将可视化我想要做的事情:

  • 假设夜间时间为23:00至06:00。
  • 我们有DateTime1 = 20-04-2016 13:30
  • 我们有DateTime2 = 21-04-2016 07:15
  • 夜间:从23:00到06:00 = 7小时0分钟。
  • DayTime:从13:30到23:00(9h30m),然后是第二天06:00到07:15(1h15m),总共 10小时45分钟。

我正在提供create table查询,但我只需要计算方面的帮助,因此您可以忽略我的表和数据。请注意,我删除了几乎所有格式以减少,因为帖子很长。

CREATE TABLE [dbo].[myTestTable](
    [JHID] [int] NULL,        [ToDateTime] [datetime] NULL,
    [startPayDateTime] [datetime] NULL,     [opDayHour] [int] NULL,
    [opDayMin] [int] NULL,      [opNightHour] [int] NULL,
    [opNightMin] [int] NULL,  ) ON [PRIMARY]    GO

考虑将其作为测试数据插入。列(用于测试目的)为startPayDateTimeToDateTime

INSERT INTO [myTestTable]
           ([JHID],[ToDateTime],[startPayDateTime],[opDayHour],[opDayMin],[opNightHour],[opNightMin])
     VALUES         (301533,'14-03-2016 01:54','14-03-2016 04:54',1,1,1,1),
    (302488,'14-03-2016 01:54','14-03-2016 08:31',0,0,0,0),
    (302676,'14-03-2016 01:54','28-03-2016 08:11',1,1,1,1) GO

所以现在我必须

UPDATE 
SET opDayHour = (CASE WHEN ... THEN *value* ELSE 0 end),
    opDayMin = (CASE WHEN ... THEN *value* ELSE 0 end),
    opNightHour = (CASE WHEN ... THEN *value* ELSE 0 end),
    opNightMin = (CASE WHEN ... THEN *value* ELSE 0 end),

如果我的问题不够明确,我如何感谢您的考虑留下评论! :)

2 个答案:

答案 0 :(得分:2)

想法是检测第一天,一些洞日(如果存在)和最后一天(如果不是与第一天相同)。因此,我们只需要一天的计数表即可。缺点是那些第一个/最后一个间隔的更多计算。当你需要涉及许多中间变量的计算时,CROSS APPLY是一个方便的工具。 试试这个,您可能需要调整+ -1逻辑以符合您的规则。此查询计算分钟数,可以轻松转换为小时+分钟。

with myMinutes as (
    select rn 
        -- day time is from 6:00 to 23:00
        , mday = case when rn between 6*60 and 23*60-1 then 1 else 0 end
        , mnight = 1 - case when rn between 6*60 and 23*60-1 then 1 else 0 end
    from (select top(24*60) rn=row_number () over (order by (select null))
        from sys.all_objects s1, sys.all_objects s2) t
)
select dayMinutes=r1.dayMin + case holedays when 0 then 0 else r2.dayMin + (holedays-1)*(23*60 - 6*60) end 
    , nightMinutes=r1.nightMin + case holedays when 0 then 0 else r2.nightMin + (holedays-1)*(24*60 -(23*60 - 6*60)) end 
    , totalMinutes= datediff(MINUTE, [FromDateTime], [ToDateTime]) -- control
           ,[JHID],[JetReg],[ArrFltID],[DepFltID],[ArrDateTime],[FromDateTime],[ToDateTime]
-- more columns sipped
from  [myTestTable]
cross apply (select  fD = dateadd(DAY,datediff(DAY,'19000101',[FromDateTime]),'19000101')
                    ,tD = dateadd(DAY,datediff(DAY,'19000101',[ToDateTime]),'19000101')
                    ,holedays = datediff(DAY,[FromDateTime],[ToDateTime]) ) xd
cross apply (select  fFirstMin = datediff(MINUTE, fd, [FromDateTime])
                    ,fLastMin = case holedays when 0 then datediff(MINUTE, td,[ToDateTime]) else 24*60 end - 1
                    ,tFirstMin = 1
                    ,tLastMin = datediff(MINUTE, td, [ToDateTime]) 
                    ) xb
cross apply (select dayMin = sum(mm.mday)
                , nightMin = sum(mm.mnight)
                from myminutes mm 
                where mm.rn between fFirstMin and fLastMin ) r1
cross apply (select dayMin = sum(mm.mday)
                , nightMin = sum(mm.mnight) 
                from myminutes mm 
                where mm.rn between tFirstMin and tLastMin ) r2

答案 1 :(得分:1)

您可以使用cte作为该计数:

DECLARE
@DateTime1 datetime = '2016-04-20 13:30',
@DateTime2 datetime = '2016-04-21 07:15'

;WITH times AS(
SELECT  @DateTime1 as d,
        CASE WHEN DATEPART(hour,@DateTime1) between 6 and 22 then 'd' else 'n' end as a,
        0 as m
UNION ALL
SELECT  DATEADD(minute,1,d),
        CASE WHEN DATEPART(hour,DATEADD(minute,1,d)) between 6 and 22 then 'd' else 'n' end as a,
        DATEDIFF(minute,d,DATEADD(minute,1,d)) 
FROM times
WHERE DATEADD(minute,1,d) <= @DateTime2
)

SELECT  CASE WHEN a = 'd' THEN 'DayTime' ELSE 'NightTime' END as TimePart,
        sum(m)/60 as H,
        sum(m) - (sum(m)/60)* 60 as M
FROM times
GROUP BY a
OPTION (MAXRECURSION 0)

输出如下:

TimePart  H           M
--------- ----------- -----------
DayTime   10          45
NightTime 7           0

(2 row(s) affected)