如何找到PHP MySQL列的最后N个读数的差异的平均值

时间:2014-03-11 19:39:43

标签: php mysql sql

我在MySQL数据库(level_records)中有一个表,它有3列(id,date,reading)。我想将最近的20个读数(按日期)之间的差异放入一个数组中,然后对它们求平均值,以找出平均值。

我到处都是,但似乎没有人像我一样。

我将非常感谢任何帮助。感谢。

2 个答案:

答案 0 :(得分:1)

SELECT AVG(difference)
FROM (
    SELECT @next_reading - reading AS difference, @next_reading := reading
    FROM (SELECT reading
          FROM level_records
          ORDER BY date DESC
          LIMIT 20) AS recent20
    CROSS JOIN (SELECT @next_reading := NULL) AS var
    ) AS recent_diffs

DEMO

答案 1 :(得分:0)

如果我们考虑"差异"要签名,如果我们忽略/排除任何具有读取值的NULL值的行...

如果您只想返回读数与前一个读数之间差异的值(以获得最新的19个差异),那么您可以执行以下操作:

SELECT d.diff
  FROM ( SELECT e.reading - @prev_reading AS diff
              , @prev_reading                    AS prev_reading
              , @prev_reading := e.reading       AS reading
           FROM ( SELECT r.date
                       , r.reading
                    FROM level_records r
                   CROSS
                    JOIN (SELECT @prev_reading := NULL) p
                   ORDER BY r.date DESC
                   LIMIT 20
                ) e
          ORDER BY e.date ASC
       ) d

那将为你提供从MySQL返回的行,你可以在PHP中随心所欲地使用它们。 (关于如何在PHP中使用数组的问题是一个与MySQL没有任何关系的问题。)

如果您想知道如何将SQL结果集中的行返回到PHP数组中,那么这与"最新的二十三","差异&#34实际上没有任何关系;或者"平均"一点都不您使用的相同模式用于从任何查询返回结果。关于这一点没有任何独特之处,有很多例子,(大多数不幸的是使用了弃用的mysql_接口;对于新开发,你想要使用PDO或mysqli _。


如果你的意思是"所有19组差异"你希望得到阅读和其他阅读之间的区别,并为每次阅读做到这一点,这样你总共得到380行(= 20 *(20-1)行),然后:

SELECT a.reading - b.reading AS diff
     , a.id       AS a_id
     , a.date     AS a_date
     , a.reading  AS a_reading
     , b.id       AS b_id
     , b.date     AS b_date 
     , b.reading  AS b_reading 
  FROM ( SELECT aa.id
              , aa.date
              , aa.reading
           FROM level_record aa
          WHERE aa.reading IS NOT NULL
          ORDER BY aa.date DESC, aa.id DESC
          LIMIT 20
       ) a
  JOIN ( SELECT bb.id
              , bb.date
              , bb.reading
           FROM level_record bb
          WHERE bb.reading IS NOT NULL
          ORDER BY bb.date DESC, bb.id DESC
          LIMIT 20 
       ) b
 WHERE a.id <> b.id
 ORDER BY a.date DESC, b.date DESC

有时候,我们只想要在一个方向上有差异,也就是说,如果我们有r13和r15之间的差异,我们基本上已经有了逆,即r15和f13之间的差异。有时,使用反向副本会更方便。

您运行的查询实际上取决于您想要返回的结果集。


如果目标是获得平均值&#34;,那么我们知道最近20个读数之间的差异的平均值将与第一个之间的差异相同,而不是使用PHP数组进行修改。和最后的读数(最近二十),除以十九。

如果我们只想在至少有二十个读数可用的情况下返回一行,那么就像这样:

SELECT (l.reading - f.reading)/19 AS avg_difference
  FROM ( SELECT ll.reading
           FROM level_records ll
          WHERE ll.reading IS NOT NULL
          ORDER BY ll.date DESC LIMIT 1
       ) l
 CROSS
  JOIN (SELECT ff.reading
          FROM level_records ff
         WHERE ff.reading IS NOT NULL
         ORDER BY ff.date DESC LIMIT 19,1
       ) f

注意:只有在level_records表中至少有20行具有非NULL读取值时,该查询才会返回一行。

对于更一般的情况,如果表中少于20行(即少于19个差异)并且我们想要平均最新可用行之间的差异,我们可以这样做:

SELECT (l.reading - f.reading)/f.cnt AS avg_difference
  FROM ( SELECT ll.reading
           FROM level_records ll
          WHERE ll.reading IS NOT NULL
          ORDER BY ll.date DESC
          LIMIT 1
       ) l
 CROSS
  JOIN (SELECT ee.reading
             , ee.cnt 
          FROM ( SELECT e.date
                      , e.reading
                      , (@i := @i + 1) AS cnt
                   FROM level_records e
                  CROSS
                   JOIN (SELECT @i := -1) i
                  WHERE e.reading IS NOT NULL
                  ORDER BY e.date DESC
                  LIMIT 20
               ) ee
         ORDER BY ee.date ASC
         LIMIT 1
       ) f

但是,如果我们需要对待&#34;差异&#34;作为无符号(也就是说,我们取得读数之间差异的绝对值),

然后我们需要得到读数之间的实际差异,然后平均差异的绝对值......

然后我们可以使用MySQL用户变量来跟踪&#34;之前的&#34;阅读,并在我们处理下一行时可以使用,所以我们可以得到它们之间的区别,如下所示:

SELECT AVG(d.abs_diff)
  FROM ( SELECT ABS(e.reading - @prev_reading)   AS abs_diff
              , @prev_reading                    AS prev_reading
              , @prev_reading := e.reading       AS reading
           FROM ( SELECT r.date
                       , r.reading
                    FROM level_records r
                   CROSS
                    JOIN (SELECT @prev_reading := NULL) p
                   ORDER BY r.date DESC
                   LIMIT 20
                ) e
          ORDER BY e.date ASC
       ) d