获得接下来5行的平均值

时间:2014-07-28 10:53:10

标签: sql sql-server

我有这个查询,按天计算测量的平均值 现在我希望在接下来的5天内从每一行获得平均值

哦......我正在使用Sql Server

这是我的

SELECT Cast(Cast (Datepart(year, Dateadd(minute, (a.quarternumber * 15), 
            '2000-01-01')) 
                   AS 
            VARCHAR(4)) 
            + '-' 
            + Cast (Datepart(month, Dateadd(minute, (a.quarternumber * 15), 
                   '2000-01-01')) 
            AS VARCHAR(4)) 
            + '-' 
            + Cast (Datepart(day, Dateadd(minute, (a.quarternumber * 15), 
            '2000-01-01') 
                   )AS 
            VARCHAR(4)) 
            + ' ' AS DATETIME) AS [TimeStamp], 
       --AVG(a.value) over(order by a.value) as exper, 
       Round(Avg(a.value), 2)  AS Value 
FROM   measurements.archive a 
       INNER JOIN measurements.points p 
               ON a.pointid = p.id 
       INNER JOIN fifthcore..cm_lod_devices ld 
               ON ld.uuid = p.logicaldeviceuuid 
WHERE  ld.id IN (SELECT value 
                 FROM   @LodDeviceIds) 
       AND p.name = @Name 
       AND a.quarternumber BETWEEN @ChartBeginNumber AND @ChartEndNumber 
GROUP  BY Datepart(year, Dateadd(minute, ( a.quarternumber * 15 ), '2000-01-01') 
), 
          Datepart(month, Dateadd(minute, ( a.quarternumber * 15 ), '2000-01-01' 
                          )), 
          Datepart(day, Dateadd(minute, ( a.quarternumber * 15 ), '2000-01-01')) 
ORDER  BY Datepart(day, Dateadd(minute, ( a.quarternumber * 15 ), '2000-01-01')) 

我正在研究这样的事情,但却无法让它发挥作用

AVG(y) OVER(ORDER BY x
3 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)


Table                             :extra column that would avg the result of next five days 
2014-07-01 00:00:00.000 16.780000   --> 15.8 
2014-07-02 00:00:00.000 15.940000   --> 16 
2014-07-03 00:00:00.000 16.790000
2014-07-04 00:00:00.000 16.790000
2014-07-05 00:00:00.000 16.040000
2014-07-06 00:00:00.000 16.500000
2014-07-07 00:00:00.000 16.790000
2014-07-08 00:00:00.000 16.790000
2014-07-09 00:00:00.000 16.790000

2 个答案:

答案 0 :(得分:2)

我认为您的问题是您正在使用AVG()错误地使用OVER子句。

您正在使用GROUP BY - 因此同一查询中的AVG()将应用于该组,而不是整个数据集,因此您无法先使用SQL SERVER 2012特定的窗口版本做子查询或CTE。

以下是我认为你可以让它发挥作用的方式,但请注意 - 此时我还没有真正测试过它。

WITH cte AS (
    SELECT Cast(Cast (Datepart(year, Dateadd(minute, (a.quarternumber * 15), 
                '2000-01-01')) 
                       AS 
                VARCHAR(4)) 
                + '-' 
                + Cast (Datepart(month, Dateadd(minute, (a.quarternumber * 15), 
                       '2000-01-01')) 
                AS VARCHAR(4)) 
                + '-' 
                + Cast (Datepart(day, Dateadd(minute, (a.quarternumber * 15), 
                '2000-01-01') 
                       )AS 
                VARCHAR(4)) 
                + ' ' AS DATETIME) AS [TimeStamp], 
           Round(Avg(a.value), 2)  AS Value
           SUM (a.value) AS ValueSum, -- New item - required for calculating windowed average from group
           COUNT(a.value) AS ValueCount  -- New item - required for calculating windowed average from group
    FROM   measurements.archive a 
           INNER JOIN measurements.points p 
                   ON a.pointid = p.id 
           INNER JOIN fifthcore..cm_lod_devices ld 
                   ON ld.uuid = p.logicaldeviceuuid 
    WHERE  ld.id IN (SELECT value 
                     FROM   @LodDeviceIds) 
           AND p.name = @Name 
           AND a.quarternumber BETWEEN @ChartBeginNumber AND @ChartEndNumber 
    GROUP  BY Datepart(year, Dateadd(minute, ( a.quarternumber * 15 ), '2000-01-01') 
    ), 
              Datepart(month, Dateadd(minute, ( a.quarternumber * 15 ), '2000-01-01' 
                              )), 
              Datepart(day, Dateadd(minute, ( a.quarternumber * 15 ), '2000-01-01')) 
    ORDER  BY Datepart(day, Dateadd(minute, ( a.quarternumber * 15 ), '2000-01-01'))
)
SELECT 
    [TimeStamp],
    Value,
    SUM(ValueSum) OVER (
        ORDER BY [TimeStamp] ROWS BETWEEN CURRENT ROW AND 5 FOLLOWING
    ) /
    SUM(ValueCount) OVER (
        ORDER BY [TimeStamp] ROWS BETWEEN CURRENT ROW AND 5 FOLLOWING
    ) AS ValueOverNext5 
    -- Average = SUM(x) / COUNT(x) = SUM(SUM(group)) / SUM(COUNT(group))
FROM cte

如您所见,我将您的查询放在公用表表达式中,并为SUM和COUNT添加了2个新列。然后我将窗口化的AVG OVER应用于这些项目(通过执行SUM(总计)OVER(...)/ SUM(计数)OVER(...) - 来自CTE的已经平均值的直接AVG将是不正确的)

希望这有意义并且有效!

答案 1 :(得分:1)

如果您是SQL Server 2008,那就是这样 第一部分只是制作测试数据:

DECLARE @MyTable TABLE
(
    MyDate DATETIME,
    Value DECIMAL(19,6)
)

INSERT INTO @MyTable
VALUES
('2014-07-01 00:00:00.000',16.780000),
('2014-07-02 00:00:00.000',15.940000), 
('2014-07-03 00:00:00.000',16.790000),
('2014-07-04 00:00:00.000',16.790000),
('2014-07-05 00:00:00.000',16.040000),
('2014-07-06 00:00:00.000',16.500000),
('2014-07-07 00:00:00.000',16.790000),
('2014-07-08 00:00:00.000',16.790000),
('2014-07-09 00:00:00.000',16.790000);

现在我创建一个CTE订单我的数据并给它一个rownumber。

WITH SortedData AS
(
    SELECT *,
    ROW_NUMBER() OVER (ORDER BY MyDate) RN
    FROM @MyTable
)

现在使用我的CTE,我得到接下来的4行avg with。

SELECT 
CAST(t1.MyDate AS DATE) AS MyDate,
t1.Value,
t1.RN,
d.FCNT,
d.FSUM,
d.FAVG
FROM SortedData T1
OUTER APPLY
(
    SELECT 
        SUM(T2.VALUE)  FSUM,
        COUNT(1) FCNT,
        AVG(T2.Value) FAVG
    FROM SortedData T2
    WHERE T2.RN >= T1.RN
        AND T2.RN <= T1.RN + 4
) d
ORDER BY T1.RN

这是输出:

MyDate  Value   RN  FCNT    FSUM    FAVG
2014-07-01  16.780000   1   5   82.340000   16.468000
2014-07-02  15.940000   2   5   82.060000   16.412000
2014-07-03  16.790000   3   5   82.910000   16.582000
2014-07-04  16.790000   4   5   82.910000   16.582000
2014-07-05  16.040000   5   5   82.910000   16.582000
2014-07-06  16.500000   6   4   66.870000   16.717500
2014-07-07  16.790000   7   3   50.370000   16.790000
2014-07-08  16.790000   8   2   33.580000   16.790000
2014-07-09  16.790000   9   1   16.790000   16.790000

对于SQL Server 2012,它可以像这样简单: 让我们更改测试数据并为每个日期添加更多行:

DECLARE @MyTable TABLE
(
    MyDate DATETIME,
    Value DECIMAL(19,6)
)

INSERT INTO @MyTable
VALUES
('2014-07-01 00:00:00.000',1.0),
('2014-07-01 00:00:00.000',2.0),
('2014-07-01 00:00:00.000',3.0),
('2014-07-01 00:00:00.000',4.0),
('2014-07-02 00:00:00.000',7.0),
('2014-07-02 00:00:00.000',7.0),
('2014-07-02 00:00:00.000',7.0),
('2014-07-03 00:00:00.000',8.0),
('2014-07-04 00:00:00.000',9.0),
('2014-07-05 00:00:00.000',10.0),
('2014-07-06 00:00:00.000',11.0),
('2014-07-07 00:00:00.000',20.0),
('2014-07-08 00:00:00.000',25.0),
('2014-07-09 00:00:00.000',50.0);

现在让我们的CTE组和AVG成为数据:

WITH SortedData AS
(
    SELECT
        MyDate,
        AVG(VALUE) DayAvg,
        ROW_NUMBER() OVER (ORDER BY MyDate) RN,
        AVG(AVG(VALUE)) OVER (ORDER BY MyDate ROWS between current row and 4 following) FDAVG
    FROM @MyTable
    GROUP BY MyDate
)

SELECT CAST(sd.MyDate AS DATE) AS MyDate,
    sd.DayAvg,
    sd.RN,
    sd.FDAVG
FROM SortedData sd

这是输出:

MyDate  DayAvg  RN  FDAVG
2014-07-01  2.500000    1   7.300000
2014-07-02  7.000000    2   9.000000
2014-07-03  8.000000    3   11.600000
2014-07-04  9.000000    4   15.000000
2014-07-05  10.000000   5   23.200000
2014-07-06  11.000000   6   26.500000
2014-07-07  20.000000   7   31.666666
2014-07-08  25.000000   8   37.500000
2014-07-09  50.000000   9   50.000000