2016-04-20 172 views
1

我正在处理一个SQL问题。我有一个查询使临时表,使用其他几个表中的数据填充它,进行一些计算和更新,并将这些数据提供给应用程序。最后一步是计算两个日期之间有多少个小时以及多少分钟,但是它们应该分为dayHours,dayMins,nightHours,nightMins(日期时间可以在两次之间)。下面的要点将形象化我想要做的事情:SQL计算两个日期时间值之间的DayTime和NightTime

  • 比方说,晚上的时间是从23:00到06:00。
  • 我们有DateTime1 = 20-04-2016 13:30
  • 我们有DateTime2 = 21-04-2016 07:15
  • 夜间时间:从23:00到06:00 = 7小时0分钟。
  • 日间时间:从13:30到23:00(9h30m),然后再从06:00到第二天的06: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), 

我怎样感谢您的考虑,如果我的问题不够明确发表评论! :)

+0

你有没有看过[DATEDIFF](https://msdn.microsoft.com/en-us/library/ms189794.aspx)? –

+0

@BerndLinde是的。我的第一个想法是采取DATEDIFF(MINUTE,StartDate,EndDate)。我通常是一个C#开发人员,在那里我会做一个循环到开始移动或夜移,并在最后添加剩余部分。我试图在SQL中这样做,但无济于事。 –

+0

计算两个日期之间传递的整个天数:'DATEDIFF(day,dt1,dt2)'。对于每一整天你知道它有多少个日夜分钟。然后为部分日子添加日夜时间。它可能需要一堆嵌套的'case'表达式,但不需要循环。 –

回答

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) 
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 
相关问题