显示数据集的平均值,不同的日期/时间范围

时间:2015-09-26 07:57:32

标签: sql-server moving-average

DB:MS SQL Server 11.0.3156。

我有一张表,用于记录周期性数据值。关键栏目是: fldObjectGUID(varchar),fldDataTimestamp(datetime),fldConfigItem(varchar),fldConfigItemValue(numeric)

我想检索不同时间范围(日,周,月)的数据。但是为了将返回的数据点数保持在可管理的数量(例如,小于< 350),因此,我希望得到平均数。

例如:

  • Day - 返回所有数据(已经有了!)
  • 周 - 按小时平均值返回数据(例如,将有24 * 1小时平均值,* 7天)
  • 月 - 以3小时平均值(例如8 *平均值)返回数据 超过3小时,* 30)
  • 每年 - 以每日平均值(例如1 *平均值)返回数据 超过24小时,* 365)

此处显示了一个小数据集示例:

    +--------------------------------------------------------------------------------+
+ fldObjectGUID | fldRecordUpdatedTimestamp | fldConfigItem     | fldConfigItemValue |
+ 40010000      | 2015-06-16 18:20:48.000   | ICMPResponseTime  |   4.00             |
+ 40010000      | 2015-06-16 19:22:00.000   | ICMPResponseTime  |   15.00            |
+ 40010000      | 2015-06-16 20:22:14.000   | ICMPResponseTime  |   4.00             |
+ 40010000      | 2015-06-17 17:35:19.000   | ICMPResponseTime  |   6.00             |
+ 40010000      | 2015-06-17 18:36:26.000   | ICMPResponseTime  |   4.00             |
+ 40010000      | 2015-06-28 02:18:31.000   | ICMPResponseTime  |   19.00            |
+ 40010000      | 2015-06-28 03:18:54.000   | ICMPResponseTime  |   9.00             |
+ 40010000      | 2015-06-02 17:25:16.000   | ICMPResponseTime  |   3.00             |
+------------------------------------------------------------------------------------+

以不同的速率为对象(fldObjectGUID)添加数据。这可以是每5分钟一行或每小时一行。数据可能存在差距(数小时甚至数天)。我想在不同的时间帧上绘制每个对象的fldConfigItemValue数据;日(最后24小时),周,月和年。返回数据的周期不需要准确。因此,一个月可能只是过去30天,或者仅仅是从今天开始的1个日历月。

SQL只需返回单个fldObjectGUID和fldConfigItem组合的数据 - 然后我会在运行时修改SQL以获取所需对象/ configitem的数据。

数据中可能存在间隙,因此在给定时间段内没有数据点。因此,返回值可以为零。

我使用Classic ASP检索数据,创建SQL语句并解析结果。我可以在我的ASP代码中以编程方式实现结果。所以对于周'必需的设置,我可以使用AVERAGE函数重复调用DB,并使用WHERE子句检索记录的子集(NOW到NOW - 1小时)。存储该值,然后使用WHERE子句重复(NOW - 1小时到现在 - 2小时)。然后回过头来,直到我获得一周的所有价值。 “月”'和'每年'例程将是相同的,只是WHERE子句中的不同时间帧。

然而,即使对我而言,这似乎是一种笨拙的做法,只有一个SQL例程(或者周,月和年的不同SQL例程)必须更快和/或更优雅。

目前,我有一些SQL(来自StackOverflow?),我认为可能会工作,我的代码会为“月份”构建SQL。像这样的视图(我在示例中对fldObjectGUID和fldConfigItem进行了硬编码,以使示例更清晰):

SELECT      top 30 convert(date, l.fldDataTimestamp) as 'fldDataTimestamp_result', l.fldConfigItemValue, l.fldConfigItemValue
FROM        tblObjectHealthCheckData_Historic l
            INNER JOIN  (
            SELECT    MIN(fldDataTimestamp) first_timestamp
            FROM     tblObjectHealthCheckData_Historic
            where fldObjectGUID = '10050400' and fldConfigItem = 'AvailableRAM'
            group by Convert(Date, fldDataTimestamp)
            ) sub_l ON (sub_l.first_timestamp = l.fldDataTimestamp)
where fldObjectGUID = '10050400' and l.fldConfigItem = 'AvailableRAM'
order by fldDataTimestamp desc  

但这只是每天的第一个数据点(正如你可以猜到的那样,虽然我理解SQL和编程,但它们是一种爱好,而不是我为生活所做的事情)所以我很难挣扎到修复此代码。

我假设人们同意,在编写许多单独的SQL调用的代码中执行此操作会更有效率 - 但任何人都可以提供帮助吗?

1 个答案:

答案 0 :(得分:2)

我会尝试使用DATEPART函数,这样你就可以得到fldRecordUpdatedTimestamp的不同部分,然后是AVG字段fldConfigItemValue。

这可以归结为您的时间戳的一个小时(可能是分钟,在T-SQL中检查DATEPART的MSDN),因此如果您希望每周获得每日平均值,那么您需要包括:

day_fldRecordUpdatedTimestamp
week_fldRecordUpdatedTimestamp

这将是每周内每天的平均值。

下面的示例显示了每月的平均值 - 请注意,如果您有超过一年的数据,请确保包含year_fldRecordUpdatedTimestamp等。

WITH PartsTable As 
(
    SELECT
        fldObjectGUID
        , fldRecordUpdatedTimestamp
        , fldConfigItem
        , fldConfigItemValue
        , DATEPART(HOUR, fldRecordUpdatedTimestamp) As hour_fldRecordUpdatedTimestamp
        , DATEPART(DAY, fldRecordUpdatedTimestamp) As day_fldRecordUpdatedTimestamp
        , DATEPART(WEEK, fldRecordUpdatedTimestamp) As week_fldRecordUpdatedTimestamp
        , DATEPART(MONTH, fldRecordUpdatedTimestamp) As month_fldRecordUpdatedTimestamp
        , DATEPART(YEAR, fldRecordUpdatedTimestamp) As year_fldRecordUpdatedTimestamp
    FROM
        YourLogTable
    --WHERE
    -- Perhaps set a limit here to not get a huge set in the first step.    
)
SELECT
    COUNT(1) As setcount /* Shows how many rows are in each AVG calculation. */
    , fldObjectGUID
    , fldConfigItem
    , month_fldRecordUpdatedTimestamp /* Change this column for specific span you're intrested in. */
    , AVG(fldConfigItemValue) As avg_fldConfigItemValue
FROM
    PartsTable
GROUP BY
    fldObjectGUID
    , fldConfigItem
    , month_fldRecordUpdatedTimestamp /* Change this column for specific span you're intrested in. */
;

最后一点说明:确保在SELECT和GROUP BY中包含month_,week_ etc.列。