MYSQL SELECT AVG()满足一定条件的行

在我的DB是成千上万的行。 我试图计算股票或外汇的RSI。

RSI(14)的公式是:

 100 - (100 / 1 + RS ) 

RS是平均收益/平均亏损。

该公式回顾过去的14行(包括当前行),并对存在增长(或向上移动)的行的值进行平均,并将该平均值除以存在损失的行的平均值。

我在MySQL中遇到的问题是select前14行的平均增益和平均损失。 这在Excel中很容易做到。 在Excel中,我创build一个分析是否有增益或损失,然后使用AVERAGEIF(Range,Criteria,Average_Range) 。 没问题。 但是Excel不能处理大量我必须分析的行。

我曾经想过这样的事情:

 SELECT *, id, (SELECT 10000 * Avg(close - open) FROM `2011` WHERE id <= 25 AND id >= ( 25 - 13 ) AND ( close - open ) >= 0) / (SELECT 10000 * Avg(open - close) FROM `2011` WHERE id <= 25 AND id >= ( 25 - 13 ) AND ( open - close ) > 0) FROM `2011` LIMIT 50 

限制50只是保持可控性。 但是这并没有达到我想要的效果。 它的math部分是正确的,但它重复每行相同的数字。

所以当它在第25行时,它将查看第12行到第25行。然后,对于第26行,它将查看第13行到第26行等,这将成为每行的新数字。 相反,上面的SELECT语句在最后一列重复相同的数字,对于每一行应该是不同的,因为它具有与其他所有不同的范围。

以下是expression查询的一种更简单的方法:

 select t.*, 100 - (100 / (1 + avg(case when close - open > 0 then close - open end)/avg(case when open - close > 0 then open - close end)) ) as RS14 from `2011` t join `2011` t2 on t2.id between t.id - 14 and t group by t.id 

我不能发誓,它会走得更快,但可能会。 你也应该有一个id的索引。

如果你真的需要这样的function,你可以切换数据库吗? SQL Server 2012,Oracle和Postgres都提供了可用于此类查询的累积和function。

我一直在考虑这个问题,并且可以高效地进行查询。 也许更痛苦的方式是明确的join:

 select from `2011` t0 join `2011` t1 on t0.id = t1.id + 1 join `2011` t2 on t0.id = t1.id + 2 join . . . 2011` t13 on t0.id = t13.id + 13 

您需要使用不同表格中的14个variables来计算出所需的expression式。 但是,这将有效地使用ID上的索引,应该是快速(可能会比写更快)。

另一种方法是从观察你可以很容易地得到每一个第14个值:

 select ((t.id-1) div 14)*14, 100 - (100 / (1 + avg(case when close - open > 0 then close - open end)/avg(case when open - close > 0 then open - close end)) from `2011` t group by ((t.id-1) div 14) 

expression式可能不完全正确。 这个想法是使用聚合将14个行组合在一起。

现在,我们可以通过执行来获得中间行:

 select (((t.id-1 + offset) div 14))*14+offset, 100 - (100 / (1 + avg(case when close - open > 0 then close - open end)/avg(case when open - close > 0 then open - close end)) from `2011` t cross join (select 0 as offset union all select 1 union all . . . select 13 ) offsets group by (((t.id-1 + offset) div 14))*14+offset 

这是cross join来获取中间的行。

后两者中的任何一个都应该performance得相当好。 我会group by解决scheme去解决这个问题,因为编写,维护和修改起来更容易。

问题在于MySQL不会自动执行电子表格所做的工作,即根据外部查询中的id调整子查询。

你需要一个相关的子查询,像这样:

 SELECT A.*, A.id, (SELECT 10000 * AVG(B.close - B.open) FROM `2011` B WHERE B.id <= A.id AND B.id >= ( A.id - 13 ) AND (B.close - B.open) >= 0 / (SELECT 10000 * AVG(C.open - C.close) FROM `2011` C WHERE C.id <= A.id AND C.id >= (A.id - 13) AND (C.open - C.close) > 0) FROM `2011` A LIMIT 50