SQL装箱整小时

问题描述 投票:0回答:2

我正在尝试将开始时间和结束时间按整小时计时,并计算每小时使用的秒数。以整小时计算,我的意思是例如15:00:00到16:00:00。由于在午夜和跨越行的边界问题,我无法找出在SQL中执行此操作的方法。我有以下输入和输出:

Table data:

Start                       End
2020-03-06 15:30:40.000     2020-03-06 17:09:01.000
2020-03-06 22:47:52.000     2020-03-06 23:48:52.000
2020-03-06 23:49:52.000     2020-03-07 00:47:52.000
2020-03-09 17:05:26.000     2020-03-09 18:05:26.000
2020-03-09 18:05:32.000     2020-03-09 19:05:26.000


Columns in the output are: Year Month Day Hour SecondsInFullHour
Output (query on 2020-03-06)
.
.
.
2020 03 06 12 0
2020 03 06 13 0
2020 03 06 14 0
2020 03 06 15 1760
2020 03 06 16 3600
2020 03 06 17 541
2020 03 06 18 0
2020 03 06 19 0
2020 03 06 20 0
2020 03 06 21 0
2020 03 06 21 0
2020 03 06 22 728
2020 03 06 23 3540 (truncated due to day limit of 00:00:00 the following day)

Output (query on 2020-03-07)
2020 03 07 00 2872 (calculated from row 3)

Output (query on 2020-03-09)
2020 03 09 17 3274
2020 03 09 18 3594
2020 03 09 19 326

我想像上面的示例一样在特定的日期进行查询(后来我也将尝试每周执行一次,并在全天执行相同的操作),但是对于整小时的装箱操作,我尝试使用此SQL脚本:

  select Duration, datepart(HOUR, Start) AS hourN, datepart(day, Start) AS dayN
  from [dbo].[DataInput]
  where Start >= '2020-03-06 00:00' and Start <= '2020-03-06 23:59' 
  group by
  datepart(day, Start),  datepart(HOUR, Start)

在我的数据行中,我还有一个名为“持续时间”的列,该列只是以总秒数计算的开始到结束。但是,它没有考虑跨越小时/天的时间。我正在使用SQL Server。结果是,我认为这是您通常在一小时的条形图中会发现的结果。

sql sql-server datetime time date-range
2个回答
0
投票

这里是使用临时提示表和少许蛮力的方法。

示例

Select [Date] = convert(date,DT)
      ,[Hour] = datepart(hour,DT)
      ,[Seconds]=sum(1)
 From (
        Select B.* 
              ,DT=DateAdd(SECOND,N,[Start])
        From  #YourTable A
        Cross Apply ( Select Top (datediff(second,[Start],[End])) 
                             N=-1+Row_Number() Over (Order By (Select NULL)) 
                       From  master..spt_values n1, master..spt_values n2 
                    ) B
      ) A
 Group By convert(date,DT)
         ,datepart(hour,DT)
 Order By [Date],[Hour]

返回

Date        Hour    Seconds
2020-03-06  15      1760
2020-03-06  16      3600
2020-03-06  17      541
2020-03-06  22      728
2020-03-06  23      3540
2020-03-07  0       2872
2020-03-09  17      3274   <<  Not clear if you wanted a WHERE 
2020-03-09  18      3594   <<
2020-03-09  19      326    <<

0
投票

可能的方法-不是最漂亮的,也许不是最好的方法-并且不确定它是否可以在您可能拥有的所有期间都适用

https://dba.stackexchange.com/questions/174035/split-duration-hourly-depending-on-start-and-end-time改编的代码

declare @workdate datetime = '2020-03-06'
;
-- may need more rows here depending on how long the events can be
WITH E1(N) AS (
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
                ), 
numbers (n) AS ( SELECT top 24 row_number() over (order by a.n) - 1 FROM E1 a, E1 b)
, inpdata as
(
select convert(datetime, starttime) as Start_timestamp
     , convert(datetime, Endtime) as End_timestamp
from (values ('2020-03-06 15:30:40.000', '2020-03-06 17:09:01.000')
            ,('2020-03-06 22:47:52.000', '2020-03-06 23:48:52.000')
            ,('2020-03-06 23:49:52.000', '2020-03-07 00:47:52.000')
            ,('2020-03-09 17:05:26.000', '2020-03-09 18:05:26.000')
            ,('2020-03-09 18:05:32.000', '2020-03-09 19:05:26.000')
     ) t (Starttime, Endtime)
)
, workday as
(
SELECT 
   convert(varchar(13), start_final, 121) as period
 , convert(date, start_final) as perioddt
 , sum(DATEDIFF(second, start_final, end_final)) Duration
FROM
(
    SELECT Start_timestamp
    , End_Timestamp
    , CASE WHEN t.Start_timestamp > n.start_from_numbers THEN t.Start_timestamp ELSE n.start_from_numbers END start_final
    , CASE WHEN t.End_timestamp > n.end_from_numbers THEN n.end_from_numbers ELSE t.End_timestamp END end_final
    FROM inpdata t
    CROSS APPLY
    (
        SELECT dateadd(hour, n.n + datediff(hour, 0, t.Start_timestamp), 0) start_from_numbers
        , dateadd(hour, 1 + n.n + datediff(hour, 0, t.Start_timestamp), 0) end_from_numbers
        FROM numbers n WHERE DATEDIFF(HOUR, t.Start_timestamp, t.End_Timestamp) >= n.n
    ) n
) t2
group by convert(varchar(13), start_final, 121)
,convert(date, start_final)

)
select workdate
     , coalesce(work.duration, 0) as duration
from numbers
cross apply (select convert(varchar(13), dateadd(hour, numbers.n, @workdate), 121) as workdate) dt
outer apply (select *
             from workday wd
             where wd.period = dt.workdate
             ) work
© www.soinside.com 2019 - 2024. All rights reserved.