【问题标题】:SQL calculate DayTime and NightTime between two DateTime valuesSQL 计算两个 DateTime 值之间的 DayTime 和 NightTime
【发布时间】:2016-04-20 21:59:43
【问题描述】:

我遇到了一个 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 分钟。
  • 白天:从 13:30 到 23:00(9 小时 30 分),然后从 06:00 到次日 07:15(1 小时 15 分),总共 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),

如何感谢您的考虑,如果我的问题不够清楚,请发表评论! :)

【问题讨论】:

  • 你看过DATEDIFF吗?
  • @BerndLinde 是的。我的第一个想法是采用 DATEDIFF(MINUTE, StartDate, EndDate)。我通常是 C# 开发人员,我会在白班或夜班开始时循环,最后添加剩余部分。我尝试在 SQL 中这样做,但无济于事。
  • 计算两个日期之间经过的总天数:DATEDIFF(day, dt1, dt2)。对于每一天,您都知道它有多少昼夜分钟。然后附加部分天的白天和黑夜持续时间。它可能需要一堆嵌套的case 表达式,但不需要循环。

标签: sql sql-server


【解决方案1】:

我们的想法是检测第一天、钻孔天数(如果存在)和最后一天(如果与第一天不同)。所以我们只需要一天长的几分钟的计数表。缺点是对第一个/最后一个间隔的计算更多。当您需要涉及许多中间变量的计算时,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

【讨论】:

    【解决方案2】:

    您可以使用 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)
    

    【讨论】:

      猜你喜欢
      • 2020-06-30
      • 1970-01-01
      • 2010-09-17
      • 1970-01-01
      • 1970-01-01
      • 2020-07-17
      • 2013-07-11
      • 2018-12-16
      • 1970-01-01
      相关资源
      最近更新 更多