使用聚合函数生成的列

时间:2017-04-06 21:36:31

标签: mysql

起点

假设我有一个表devTest,如下所示:

+----+------+  
| id | j    |  
+----+------+  
|  1 |    5 |  
|  2 |    9 |  
|  3 |    4 |  
|  4 |    7 |  
+----+------+

目标

我想要一个列,指定行与j列中的平均值的偏差(以标准偏差表示)。也就是说,表格看起来像这样:

+----+------+------------+
| id | j    | jDev       |
+----+------+------------+
|  1 |    5 | -0.5637345 |
|  2 |    9 | 1.2402159  |
|  3 |    4 | -1.0147221 |
|  4 |    7 | 0.3382407  |
+----+------+------------+

我尝试了什么

>alter table devTest add column jDev decimal as ((j - avg(j)) / std(j));

我收到一个错误,指出聚合函数不能用于生成列的定义中:

ERROR 1901 (HY000): Function or expression 'avg()' cannot be used in the 
GENERATED ALWAYS AS clause of `jDev`

制作这种专栏必须非常普遍,所以我很想知道最佳解决方案!

2 个答案:

答案 0 :(得分:1)

此错误有意义,因为您的表格中的任何更改(例如,您添加值为0的j)都会更新您的平均值,而这反过来会更改您生成的所有列。所以这对于查询引擎来说将是相当多的工作。

另一种解决方案是改为定义视图:

CREATE VIEW j_dev (id, j, j_dev) AS 
SELECT id, j, 
       (j - avg(j)) / std(j) as j_dev
FROM devTest

(不确定创建视图语法,如果我错了,请纠正我)

答案 1 :(得分:1)

在标准SQL中,您可以:

select id, j, (j - avg(j) over ()) / std(j) over () as jdev
from devtest;

但MySQL不支持AVG OVER等分析窗口函数。因此在MySQL中,您必须单独选择聚合值:

select d.id, d.j, (d.j - agg.javg) / agg.jstd as jdev
from devtest d
cross join (select avg(j) as javg, std(j) as jstd from devtest) agg;

然后创建一个视图Benjamin Crouzier在他的回答中建议:

CREATE VIEW v_devtest AS
  select d.id, d.j, (d.j - agg.javg) / agg.jstd as jdev
  from devtest d
  cross join (select avg(j) as javg, std(j) as jstd from devtest) agg;

计算列只能从同一记录中的其他值计算其值。因此,无法使用计算列来完成您要执行的操作。