7

ハードウェアの統計を格納するテーブルが SQL Server にあり、テーブル内の行は特定の秒のデータを表します。たとえば、次の列が含まれます。

timestamp (DateTime)
value (int)

私がしたいのは、特定の日付/時刻範囲のテーブルからデータを選択することですが、特定の期間 (1 分、5 分、1 日など) の平均値を返すように返すことです。範囲。したがって、1 時間の場合、1 分間の平均が 60 行になります。

どこから始めればよいですか?ポイントやアイデアはありますか?

4

5 に答える 5

9

タイムスタンプの DatePart で選択とグループ化を行うことができます。

例えば:

SELECT
    DATEPART(hh, [timestamp]),
    DATEPART(mi, [timestamp]),
    AVG([value])
FROM
    YourTable
WHERE
    [timestamp] BETWEEN '2009-01-01 00:00:00.000' AND '2009-02-01 00:00:00.000'
GROUP BY
    DATEPART(hh, [timestamp]),
    DATEPART(mi, [timestamp])

編集: 5 分のようなより複雑な期間については、次のように日付部分を分割できます。

DATEPART(mi, [timestamp]) / 5 * 5
于 2009-06-16T11:44:21.017 に答える
5
WITH    cal(m) AS
        (
        SELECT  1
        UNION ALL
        SELECT  m + 1
        FROM    cal
        WHERE   m < 60
        )
SELECT  DATEADD(minute, m, @start), AVG(value)
FROM    cal
LEFT JOIN
        timestamp
ON      timestamp > DATEADD(minute, m, @start)
        AND timestamp <= DATEADD(minute, m + 1, @start)
GROUP BY
        m

これにより、レコードがない場合でも、特定の時間内のすべての分の平均が選択されます。

于 2009-06-16T11:48:22.367 に答える
1

このデータの読み取り/書き込み比率を高くする場合は、インデックス付きビューを検討することをお勧めします。私はこのアプローチをいたるところで使用して、時間のバケットごとに集計しました。サンプルのブログを書き始めたところです。コードは次のとおりです。

create table timeSeries (
    timeSeriesId int identity primary key clustered
    ,updateDate datetime not null
    ,payload float not null
)

insert timeSeries values ('2009-06-16 12:00:00', rand())
insert timeSeries values ('2009-06-16 12:00:59', rand())
insert timeSeries values ('2009-06-16 12:01:00', rand())
insert timeSeries values ('2009-06-16 12:59:00', rand())
insert timeSeries values ('2009-06-16 01:00:00', rand())
insert timeSeries values ('2009-06-16 1:30:00', rand())
insert timeSeries values ('2009-06-16 23:59:00', rand())
insert timeSeries values ('2009-06-17 00:01:00', rand())
insert timeSeries values ('2009-06-17 00:01:30', rand())


create view timeSeriesByMinute_IV with schemabinding as
select
    dayBucket = datediff(day, 0, updateDate)
    ,minuteBucket = datediff(minute, 0, (updateDate - datediff(day, 0, updateDate)))
    ,payloadSum = sum(payLoad)
    ,numRows = count_big(*) 
from dbo.timeSeries
group by 
    datediff(day, 0, updateDate)
    ,datediff(minute, 0, (updateDate - datediff(day, 0, updateDate)))
go

create unique clustered index CU_timeSeriesByMinute_IV on timeSeriesByMinute_IV (dayBucket, minuteBucket)
go


create view timeSeriesByMinute as
select
    dayBucket
    ,minuteBucket
    ,payloadSum
    ,numRows
    ,payloadAvg = payloadSum / numRows
from dbo.timeSeriesByMinute_IV with (noexpand)
go

declare @timeLookup datetime, @dayBucket int, @minuteBucket int
select 
    @timeLookup = '2009-06-16 12:00:00'
    ,@dayBucket = datediff(day, 0, @timeLookup)
    ,@minuteBucket = datediff(minute, 0, (@timeLookup - datediff(day, 0, @timeLookup)))

select * from timeSeriesByMinute where dayBucket = @dayBucket and minuteBucket = @minuteBucket

コード ブロックの最後にルックアップの例があります。特定の dayBucket/minuteBucket ペアをシークするだけでなく、クエリの範囲を定義できることは明らかです。

于 2009-06-16T13:40:11.627 に答える
1

Robin Day の投稿に加えて、次のように 5 分間隔でグループ化できます。

GROUP BY
    DATEPART(hh, [timestamp]),
    DATEPART(mi, [timestamp]) / 5

また、数日にまたがる場合は、dy でグループ化し、年間通算日を指定します。

GROUP BY
    DATEPART(dy, [timestamp]),
    DATEPART(hh, [timestamp]),
    DATEPART(mi, [timestamp]) / 5
于 2009-06-16T11:48:58.120 に答える