我在MySQL数据库(level_records)中有一个表,它有3列(id,date,reading)。我想将最近的20个读数(按日期)之间的差异放入一个数组中,然后对它们求平均值,以找出平均值。
我到处都是,但似乎没有人像我一样。
我将非常感谢任何帮助。感谢。
答案 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
答案 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