SQL timeboxing за полный час - PullRequest
       29

SQL timeboxing за полный час

0 голосов
/ 09 марта 2020

Я пытаюсь синхронизировать время начала и окончания на полный час и подсчитать, сколько секунд за каждый использованный час. С полным часом я имею в виду, например, с 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

Я бы хотел запросить в конкретный c день, как в примерах выше (позже я постараюсь реализовать также в неделю и сделать то же самое в полный рабочий день), но для часового ящика на целый час я попытался использовать этот скрипт 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 Сервером. Результатом является то, что я считаю, это то, что вы обычно находите на часовом графике.

Ответы [ 2 ]

0 голосов
/ 14 марта 2020

возможный способ - не самый красивый и, вероятно, не самый лучший - и не уверен, что он будет работать для всех периодов, у вас может быть

код, адаптированный с 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
0 голосов
/ 09 марта 2020

Вот подход, который использует ad-ho c таблицу подсчета и небольшую грубую силу.

Пример

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    <<
...