Усреднение TSQL по дате - PullRequest
1 голос
/ 15 ноября 2011

У меня есть таблица со столбцом datetime, я считаю ее журналом событий для простых, аналогичных целей.

Я хочу создать отчет с подробным описанием среднего числа событий, происходящих в каждое время дня.с точностью до 30 минут.

, поэтому логика такова:

  • получить только компонент времени каждой даты
  • вокруг времени до ближайшего окна 30 минут (он может быть обработан, т. е. 00:29 -> 00:00)
  • считать их (сгруппированные по дате)
  • усреднять все эти подсчеты за все дни

Я также не хочу иметь никаких временных пробелов в моих данных, например, если ничего не произошло в диапазоне 00:00 - 00:30, я хочу сообщить 0, а не пропустить строку.

Как мне этого добиться?

Ответы [ 4 ]

1 голос
/ 15 ноября 2011
WITH TestDates (date) AS (
    SELECT CONVERT(DATETIME, '2011-11-15 10:00') UNION ALL
    SELECT CONVERT(DATETIME, '2011-11-15 11:31') UNION ALL
    SELECT CONVERT(DATETIME, '2011-11-16 10:00')

-- CTE to generate 4 million rows with a sequential integer starting at 0
), GeneratedRows (seq) AS (
    SELECT ROW_NUMBER() OVER (ORDER BY N1.number) - 1
      FROM master..spt_values AS N1
     CROSS JOIN master..spt_values AS N2
     WHERE N1.name IS NULL
       AND N2.name IS NULL

), RoundedTestDates (date) AS (
    SELECT CASE
             -- Subtract the minute part
             WHEN DATEPART(MINUTE, date) <  25 THEN DATEADD(MINUTE, -1 * DATEPART(MINUTE, date), date)
             -- Subtract the minute part, then add an hour
             WHEN DATEPART(MINUTE, date) >= 45 THEN DATEADD(HOUR, 1, DATEADD(MINUTE, -1 * DATEPART(MINUTE, date), date))
             -- Subtract the minute part, then add an half-hour
             ELSE DATEADD(MINUTE, 30, DATEADD(MINUTE, -1 * DATEPART(MINUTE, date), date))
           END
      FROM TestDates
)

SELECT rounded_date = GeneratedPeriod.date
     , ocurrences   = COUNT(RoundedTestDates.date)
  FROM (SELECT DATEADD(MINUTE, 30 * seq, (SELECT MIN(date) FROM RoundedTestDates))
          FROM GeneratedRows
       ) AS GeneratedPeriod (date)
  LEFT JOIN RoundedTestDates
    ON GeneratedPeriod.date = RoundedTestDates.date
 WHERE GeneratedPeriod.date <= (SELECT MAX(date) FROM RoundedTestDates)
 GROUP BY GeneratedPeriod.date
 ORDER BY 1
1 голос
/ 15 ноября 2011

Вот код, который вам нужен: (протестирован в sql2008 и работает отлично!)

-- Table with the 48 30mins periods of the day
CREATE TABLE #Periods
(
Num INT 
)    
DECLARE @idt INT
SET @idt = 1
WHILE (@idt <= 48)
BEGIN
INSERT INTO #Periods VALUES (@idt)
SET @idt = @idt + 1
END
--Average of the count for each period on all days.
SELECT DayTable.Num, AVG(CAST(DayTable.DayCount AS DECIMAL))
FROM
(   --Total incidents for each interval on each day.
    SELECT CAST(FLOOR(CAST(#MyLog.LogDate AS FLOAT)) AS DATETIME) AS DayWithOutTime,
           #Periods.Num AS Num, 
           COUNT(#MyLog.ID) AS DayCount
    FROM #Periods LEFT JOIN #MyLog
            ON #Periods.Num = (DATEPART(hh, #MyLog.LogDate)*60 + DATEPART(mi,#MyLog.LogDate))/30
    GROUP BY CAST(FLOOR(CAST(#MyLog.LogDate AS FLOAT)) AS DATETIME),
             #Periods.Num
) AS DayTable
GROUP BY DayTable.Num

DROP TABLE #Periods 

Где #NyLog - таблица, в которой находится ваше время. Он показывает количество инцидентов за каждый 30-минутный период. Период 1 - 00:00 -> 00:30, а период 48 - 23:30 -> 24:00.

0 голосов
/ 27 марта 2012

Я использовал вспомогательную таблицу чисел (таблицу из 1 столбца с номерами от 1 до 1 миллиона) и присоединился к ней, добавив значение числа с помощью функции dateadd к полуночи даты.

, так как вам нужны 30-минутные интервалы, вы хотите использовать dateadd (минуты, числа * 30, ваши даты), где число <= 48 (поскольку в дне 1440 минут) / 30 = 48 интервалов. Это создаст ваши временные интервалы. </p>

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

0 голосов
/ 15 ноября 2011

В sybase sql примерно так, в sql-сервере вам может потребоваться внести некоторые изменения, но не намного:)

create procedure Test @startDay varchar(8), @endDay varchar(8)
as

declare @ocurrence int

declare @numberOfDays int
select @numberOfDays = 0

create table #intervals (
    interval_hour int,
    interval_min_minute int,
    interval_max_minute int,
    ocurrences int
)

create table #insertions (
    hour int,
    minute int
)

declare @hour int, @minute int
select @hour = 0


-- create the intervals
while (@hour <> 24)
begin
    insert into #intervals values(@hour,0,29,0)
    insert into #intervals values(@hour,30,59,0)

    select @hour = @hour + 1
end


while(@startDay <> @endDay)
begin
    insert into #insertions
    select datepart(hh, *yourcolumn*), datepart(mm, *yourcolumn*) from *yourdb..yourtable* where convert(varchar(8), *yourcolumn*, 112) = @startDay

    select @startDay = convert(varchar(8), dateadd(dd, 1, convert(datetime, @startDay, 112)), 112)
    select @numberOfDays = @numberOfDays + 1
end



declare cursor1 cursor for
select hour, minute from #insertions


open cursor1
fetch cursor1 into @hour, @minute

while (@@sqlstatus=0)
begin


update #intervals
set i.ocurrences = i.ocurrences + 1
from #intervals i
where interval_hour = @hour and @minute between interval_min_minute and interval_max_minute

fetch cursor1 into @hour, @minute
end

close cursor1

select interval_hour 'hour', interval_min_minute 'min minute', interval_max_minute 'max minute', ocurrences,
    case when ocurrences > 0 then convert(float, ocurrences) / convert(float, @numberOfDays) else 0 end 'ocurrences average' from #intervals

drop table #intervals
drop table #insertions

go 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...