MYSQL选择满足中某些条件的行的平均值()
在我的数据库中有数十万行。我试图计算股票或外汇的相对标准差指数 RSI14的公式为: RS是平均增益/平均损耗 该公式回顾过去的14行,包括当前行,并对有增益或向上移动的行的值进行平均,然后将该平均值除以有损耗的行的平均值 我在MySQL中遇到的问题是让它为前14行选择平均增益和平均损耗。这在Excel中很容易做到。在Excel中,我创建了一个列,分析是否存在收益或损失,然后使用AVERAGEIFRange、Criteria、Average_Range。没问题。但是Excel无法处理我必须分析的大量行 我曾经想过这样的事情:MYSQL选择满足中某些条件的行的平均值(),mysql,excel,average,Mysql,Excel,Average,在我的数据库中有数十万行。我试图计算股票或外汇的相对标准差指数 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
t、 id>13,从'2011'中选择AVGclose-open$sql=选择日期、时间,round100-100/1+如果first.id>13,选择AVGclose-从“2011”开始打开$sql.=其中open