如何计算MYSQL中的移动平均线

时间:2018-04-10 23:45:56

标签: mysql

我有一个应用程序将股票报价存储到我的MySQL数据库中。

我有一个名为stock_history的表格:

mysql> desc stock_history;
+-------------------+---------------+------+-----+---------+----------------+
| Field             | Type          | Null | Key | Default | Extra          |
+-------------------+---------------+------+-----+---------+----------------+
| id                | int(11)       | NO   | PRI | NULL    | auto_increment |
| date              | date          | NO   | MUL | NULL    |                |
| close             | decimal(12,5) | NO   | MUL | NULL    |                |
| dmal_3            | decimal(12,5) | YES  | MUL | NULL    |                |
+-------------------+---------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)

这是表中的所有值:

mysql> select date, close, dmal_3 from stock_history order by date asc;
+------------+----------+----------+
| date       | close    |   dmal_3 | 
+------------+----------+----------+-
| 2000-01-03 |  2.00000 |     NULL | 
| 2000-01-04 |  4.00000 |     NULL | 
| 2000-01-05 |  6.00000 |     NULL | 
| 2000-01-06 |  8.00000 |     NULL | 
| 2000-01-07 | 10.00000 |     NULL | 
| 2000-01-10 | 12.00000 |     NULL | 
| 2000-01-11 | 14.00000 |     NULL | 
| 2000-01-12 | 16.00000 |     NULL | 
| 2000-01-13 | 18.00000 |     NULL | 
| 2000-01-14 | 20.00000 |     NULL | 
+------------+----------+----------+-
10 rows in set (0.01 sec)

我保证每个日期会有0或1条记录。

我可以编写一个查询,将三天移动平均线(即:当天的平均收盘价和之前的前两个交易日)插入dmal_3字段吗?怎么样?

查询完成后,我希望表格如下所示:

mysql> select date, close, dmal_3 from stock_history order by date asc;
+------------+----------+----------+
| date       | close    |   dmal_3 | 
+------------+----------+----------+
| 2000-01-03 |  2.00000 |     NULL | 
| 2000-01-04 |  4.00000 |     NULL | 
| 2000-01-05 |  6.00000 |  4.00000 | 
| 2000-01-06 |  8.00000 |  6.00000 | 
| 2000-01-07 | 10.00000 |  8.00000 | 
| 2000-01-10 | 12.00000 | 10.00000 | 
| 2000-01-11 | 14.00000 | 12.00000 | 
| 2000-01-12 | 16.00000 | 14.00000 | 
| 2000-01-13 | 18.00000 | 16.00000 | 
| 2000-01-14 | 20.00000 | 18.00000 | 
+------------+----------+----------+
10 rows in set (0.01 sec)

1 个答案:

答案 0 :(得分:2)

这就是我称之为好的挑战。我的解决方案首先为值创建一个计数器并将其用作表。从中我选择所有内容并使用与查询计数器位置的子查询相同的查询进行连接。一旦查询工作,它只需要与实际表的内部联接来进行更新。这是我的解决方案:

update stock_history tb1
   inner join 
(
select a.id, 
    case when a.step < 3 then null
    else
    (select avg(b.close) 
       from (
            select hh.*, 
                   @stp:=@stp+1 stp
              from stock_history hh,
                   (select @sum:=0, @stp:=0) x
             order by hh.dt
             limit 17823232
             ) b
      where b.stp >= a.step-2 and b.stp <= a.step
     ) 
     end dmal_3
  from (select h1.*, 
               @step:=@step+1 step
          from stock_history h1,
               (select @sum:=0, @step:=0) x
         order by h1.dt
         limit 17823232
        ) a
) x on tb1.id = x.id
set tb1.dmal_3 = x.dmal_3;

为了方便我的测试,我更改了一些列名称。这是工作的SQLFiddle:http://sqlfiddle.com/#!9/e7dc00/1

如果您有任何疑问,请告诉我,以便澄清!

修改

子查询中添加了limit 17823232子句,因为我不知道您所在的MySql版本。根据它(&gt; = 5.7,不确定),数据库优化器将忽略内部order by条款使其无法正常运行。我只是选择了一个随机的大号,通常你可以使用最大允许值。

我们的表和我的表之间唯一具有不同colunm名称的列是date,我将其命名为dt,因为date是一个保留字,你应该使用反引号(`)来使用此类列,因此我会在上面的查询中将其保留为dt