TSQL在datepart上的平均值

时间:2011-11-15 09:20:32

标签: sql sql-server sql-server-2008 tsql

我有一个带有日期时间列的表,为简单,类似的目的将其视为事件日志。

我想制作一份报告,详细说明每天发生的平均事件数,精确到30分钟。

所以逻辑是,

  • 只获取每个日期的时间部分
  • 将时间缩短到最近的30分钟窗口(可以放置,即00:29 - > 00:00)
  • 计算这些(按日期分组)
  • 平均所有这些天数

我也不希望在我的数据中有任何时间漏洞,例如,如果在00:00 - 00:30范围内没有发生任何事情,我想报告0,而不是丢失一行。< / p>

我怎样才能做到这一点?

4 个答案:

答案 0 :(得分:1)

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 :(得分:1)

以下是您需要的代码:(在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 - &gt; 00:30和48期是23:30 - &gt; 24:00。

答案 2 :(得分:0)

在sybase sql中是这样的,在sql-server中你可能需要做一些改变但不多:)

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 

答案 3 :(得分:0)

我所做的是使用一个辅助数字表(1列表,数字为1到1百万)并加入它,将数字的值与dateadd函数一起添加到日期的午夜。 / p>

因为你想要30分钟的间隔,那么你想要使用dateadd(分钟,数字* 30,你的日期),其中数字&lt; = 48(因为一天有1440分钟)/ 30 = 48间隔。这将创建您的时间间隔。

然后只计算在时间间隔之间发生的事件。