MYSQL选择满足中某些条件的行的平均值()

MYSQL选择满足中某些条件的行的平均值(),mysql,excel,average,Mysql,Excel,Average,在我的数据库中有数十万行。我试图计算股票或外汇的相对标准差指数 RSI14的公式为: RS是平均增益/平均损耗 该公式回顾过去的14行,包括当前行,并对有增益或向上移动的行的值进行平均,然后将该平均值除以有损耗的行的平均值 我在MySQL中遇到的问题是让它为前14行选择平均增益和平均损耗。这在Excel中很容易做到。在Excel中,我创建了一个列,分析是否存在收益或损失,然后使用AVERAGEIFRange、Criteria、Average_Range。没问题。但是Excel无法处理我必须分析的

在我的数据库中有数十万行。我试图计算股票或外汇的相对标准差指数

RSI14的公式为:

RS是平均增益/平均损耗

该公式回顾过去的14行,包括当前行,并对有增益或向上移动的行的值进行平均,然后将该平均值除以有损耗的行的平均值

我在MySQL中遇到的问题是让它为前14行选择平均增益和平均损耗。这在Excel中很容易做到。在Excel中,我创建了一个列,分析是否存在收益或损失,然后使用AVERAGEIFRange、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 
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
限制50只是为了保持可控。但这不是我想要的。它的数学部分做得恰到好处,但每行重复相同的数字


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

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

您需要一个相关子查询,如下所示:

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 
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

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

您需要一个相关子查询,如下所示:

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 
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

以下是表示查询的更简单方法:

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上有一个索引

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

我一直在考虑这个问题,您可以高效地执行查询。也许更痛苦的方法是使用显式连接:

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个变量计算出所需的表达式。然而,这将有效地使用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)
这些表达可能并不完全正确。其思想是使用聚合将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
这将进行交叉连接以获得中间的行


最后两个都应该表现得很好。我会选择group by解决方案,因为它更易于编写、维护和修改。

以下是一种更简单的查询表达方式:

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上有一个索引

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

我一直在考虑这个问题,您可以高效地执行查询。也许更痛苦的方法是使用显式连接:

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个变量计算出所需的表达式。然而,这将有效地使用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)
这些表达可能并不完全正确。其思想是使用聚合将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
这将进行交叉连接以获得中间的行


最后两个都应该表现得很好。我会选择分组解决方案,因为它更容易编写、维护和修改。

$sql=选择日期、时间、轮次100-100/1+如果first.id>13,选择AVGclose-openfrom`2011`$sql=选择日期、时间,round100-100/1+如果first.id>13,选择AVGclose-从“2011”开始打开$sql.=其中open=第一个id-13和id 13,从“2011”中选择AVGopen-close$sql.=WHERE open>close AND id>=first.id-13 AND id这花费了26.2669439316秒,限制为25秒。构建14天移动平均线的具体视图,这将允许您处理数据,而无需每次计算都产生巨大的开销。您能否提供表的转储以便我们运行您的查询?…我认为您可能缺少GROUP BY子句..例如,按id我没有14天移动平均数。这使用收盘价来计算RSI。$sql=选择日期、时间、整数100-100/1+iftheFirs
t、 id>13,从'2011'中选择AVGclose-open$sql=选择日期、时间,round100-100/1+如果first.id>13,选择AVGclose-从“2011”开始打开$sql.=其中open=第一个id-13和id 13,从“2011”中选择AVGopen-close$sql.=WHERE open>close AND id>=first.id-13 AND id这花费了26.2669439316秒,限制为25秒。构建14天移动平均线的具体视图,这将允许您处理数据,而无需每次计算都产生巨大的开销。您能否提供表的转储以便我们运行您的查询?…我认为您可能缺少GROUP BY子句..例如,按id我没有14天移动平均数。这使用收盘价来计算RSI。我将其与子查询关联,但这需要花费很长时间。在我最初发布之后,我发现我以前的代码是有效的,但速度非常慢。我可以试试上面建议的物化视图。@j_allen_morris。不要具体化视图,而是添加一个可以用作行号的计数器。在我最初发布之后,我发现我以前的代码是有效的,但速度非常慢。我可以试试上面建议的物化视图。@j_allen_morris。不要具体化视图,而是添加一个可以用作行号的计数器。这是我的经销商托管的服务器,我无法访问不同的程序。除了将我的一台备用计算机用作此功能的服务器外,我无法切换数据库。这是我的经销商托管的服务器,我无法访问不同的程序。除了使用我的一台备用计算机作为服务器来执行此功能外,我无法切换数据库。