【问题标题】:Get the average of each N groups获取每N组的平均值
【发布时间】:2013-12-15 20:59:14
【问题描述】:

我看到这里的一些人遇到了和我现在一样的问题......但没有任何帮助:/

我有一个包含 2 列的表 Test。日期和整数值。 我需要每 N 条记录的平均值。 比如

Date        | Info
2013-01-01  |  210
2013-01-02  |  213
2013-01-03  |  214
2013-01-05  |  197
2013-01-06  |  192

....

让我们假设 N = 3

我需要填充一个表格

Averages
212.3333 (that's the average of the 3 first Info's) (210+213+214)/3
208.0000 (213+214+197)/3
201.0000 (214+197+192)/3

我试过了

delimiter $$
DROP PROCEDURE IF EXISTS calcAvg$$
CREATE PROCEDURE calcAvg()
begin

DECLARE v_finished INTEGER DEFAULT 0;
declare v_avg DECIMAL default 0.0;
DECLARE initial_date date;

DEClARE cr CURSOR FOR 
    select avg(i) from  (
        select t.info i
           from test t
          where date >= initial_date
            limit 3
        )as s;

-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished = 1;

set initial_date = '2013-01-01';

get_avg: LOOP

    OPEN cr;

    cr_loop: LOOP

        FETCH cr INTO v_avg;

        IF v_finished = 1 THEN 
            LEAVE cr_loop;
        END IF;

        insert into result values (v_avg);

    END LOOP cr_loop;

    CLOSE cr;

    #I've to change this line... the table does not have all days
    set v_dt_ini = date_add(v_dt_ini,interval 1 DAY);
    #But the problem it's not the line yet...
    set v_finished = 0;

    if v_dt_ini > '2013-05-30' then
        leave get_avg;
    end if;

END LOOP get_avg;

end$$

在我已将 N 固定为 3 的代码中 问题是,当我调用程序时......它计算 3 条记录的第一个平均值......并且当再次执行游标时......它返回相同的值......第 3 条记录......它不是我需要什么...

光标没有改变结果:/

【问题讨论】:

  • 行是否以任何方式排序? IE。是保证日期总是增加,还是有另一个 AUTO_INCREMENT 列?这将使问题变得微不足道!
  • 是的,它有一个 id 并且日期有一个唯一索引...在这种情况下,只有日期保证...当我进行此搜索时,请选择 avg(i) from ( select t.info我来自测试 t where date >= '2013-01-01' limit 3 )as s;它使我恢复了从 2013 年 1 月 1 日开始的 3 个值的正确平均值...并且它适用于我放在代码上的所有日期...所以我将代码用作 CURSOR .. 带有变量 INITIAL_DATE我在外部循环上递增...

标签: mysql sql group-by average


【解决方案1】:

SQLFiddle

SELECT date,info,(select avg(info) from
                  (select date,info,@row1:=@row1+1 as row
                   from test,(SELECT @row1:=0)r
                   order by date desc
                  )wrn1
                  where wrn1.row between wrn2.start and wrn2.end)as avg,
       start,end

FROM
    (select date,info,@row:=@row+1 as row,(@row - 2) as start,@row as end
     from test,(SELECT @row:=0)r
     order by date desc
    )wrn2
WHERE start > 0
ORDER BY date asc

这将返回

        DATE                   INFO     AVG       START     END
January, 01 2013 00:00:00+0000     210  212.3333    3        5
January, 02 2013 00:00:00+0000     213  208         2        4
January, 03 2013 00:00:00+0000     214  201         1        3

【讨论】:

  • 我用相反的顺序做的,你可以在wrn1wrn2的查询中使用ascdesc的日期顺序,只要它们匹配他们应该工作的顺序相同。
  • 如何将其转换为 10 个平均值? @TinTran
  • @TinTran 我设法通过将@row -2 更改为@row -9 来获得前10 个值,但我不想从第二行开始获取接下来的10 个值。我该怎么做?
【解决方案2】:

您可以为此使用相关子查询。如果您想要最多 n 天(包括当前日期和之后),那么这将起作用:

select date, info,
       (select avg(t2.info)
        from test t2
        where datediff(t.date, t2.date) < n and
              t2.date >= t.date
       ) as avginfo
from test t;

如果您希望 n 记录包括当前记录和之后的记录,则以下想法可行:

select date, info,
       (select avg(info)
        from (select t2.*
              from test t2
              where t2.date >= t.date
              order by t2.date
              limit n
             ) t3
       ) as avginfo
from test t;

但是,这会在 MySQL 中产生一个错误,我不确定如何解决它(双重嵌套查询无法再识别与外部查询的相关性)。以下版本确实如here所示工作:

select t.date, t.info, avg(t3.info)
from (select date, info,
             (select t2.date
              from test t2
              where t2.date >= t.date
              order by t2.date
              limit 1 offset 2
             ) as date3
      from test t
     ) t left outer join
     test t3
     on t3.date between t.date and t.date3
group by t.date, t.info;

【讨论】:

  • 第一个工作......但不是预期值......它返回 205.20 而不是 212.3333 和其他天以相同的方式:/我尝试了第二个..但有编译错误.. . mysql 不知道子查询上的 t.date ……至少这是 MySQL 给我带来的错误:/
  • @亚瑟。 . .我解决了第一个问题(它得到了n+1 记录)。第二个是 MySQL 中的一个错误(就我而言)。我不确定解决方法是什么。
  • 但是...在我提到的 5 个示例中...平均 3 组...我只有 3 个返回...我不会有相同数量的记录...我需要的第一个值是恰好 3 个信息的平均值 第二个平均值是以下信息记录的平均值:第 2、第 3 和第 4 个第三个平均值是第 3、第 4 和第 5 个值的平均值。 .. 以此类推...直到它有 3 个值来计算新的平均值
  • @亚瑟。 . .假设日期字段一次增加一天,那么第一个查询将执行此操作。
  • @亚瑟。 . .我什至注意到您的输入数据缺少日期。答案中的最后一个版本应该可以工作。
【解决方案3】:

回应关于被订购的评论 - 诀窍是排序:

新值:使用触发器 - 原始表上的AFTER INSERT 触发器需要选择最后 N 个值的平均值 (SELECT AVG(valuecolumn) FROM table WHERE datecolumn &lt;= NEW.datecolumn ORDER BY datecolumn DESC LIMIT N) 并将其插入平均值表中。

现有值:从前到后运行此值,并使用 SELECT AVG(valuecolumn) FROM table WHERE datecolumn &lt;= NEW.datecolumn ORDER BY datecolumn ASC LIMIT M,N,M 从 0..count-2 开始

【讨论】:

  • 对不起,伙计...但是我已经提供了 10 年的信息...我会尝试 N=3、N=4、N=5.... 等等。 ..我不认为每次我想尝试某事时都触发和povoating是一件好事......除了它可以工作之外,它会花费很多性能来获取平均信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-28
  • 1970-01-01
  • 2022-11-10
  • 2020-03-09
  • 1970-01-01
  • 2015-08-03
  • 2021-09-26
相关资源
最近更新 更多