4列的平均值,具有随机空值

时间:2019-02-14 05:48:23

标签: mysql sql

我有一个员工表,其中包含4种类型的奖金。我想将每位员工的四项奖金加起来并得出平均值。有些员工没有资格获得奖金,因此这种奖金的类型不应计入其平均值。除了取笑数据库设计(这不是我的错)之外,有人在计算该平均值时是否有一种创造性的方法来忽略NULL值?

下表中唯一具有正确平均值的员工是Employee1。

SELECT title, (IFNULL(level1,0)+IFNULL(level2,0)+IFNULL(level3,0)+IFNULL(level4,0))/4 as avglevel, level1, level2, level3, level4
FROM test;
Title       avglevel    level1  level2  level3  level4
Employee1   2500.0000   1000    2000    3000    4000
Employee2   2250.0000   NULL    2000    3000    4000
Employee3   2000.0000   1000    NULL    3000    4000
Employee4   1750.0000   1000    2000    NULL    4000
Employee5   1500.0000   1000    2000    3000    NULL

我找到了此项目,但实际上它仅涵盖AVG函数,并且不除以列数,除非这些列之一为NULL时除外。 Strange MySQL AVG() anomaly NULL values

4 个答案:

答案 0 :(得分:2)

由于当前的表格设计,您需要对(而不是行)执行汇总操作。一般而言,MySQL对跨行/记录的聚合提供了强大的支持,但对列的支持则较少。如果您打算更改表设计,那么AVG函数已经可以解决此问题,因为它是开箱即用的。考虑将表存储为:

Title     | level | amount
Employee2 | 1     | NULL
Employee2 | 2     | 2000
Employee2 | 3     | 3000
Employee2 | 4     | 4000

也就是说,将每个员工的每个级别值存储在单独的记录中。然后,您可以使用以下方法轻松计算正确的平均值:

SELECT
    title,
    AVG(amount) AS avglevel
FROM test
GROUP BY
    title;

Demo

默认情况下,AVG函数将已经忽略NULL值,因此,总和将由不包括具有NULL的记录的记录计数标准化。

编辑:

在设置演示之后,您似乎想要使用所有级别归一化平均值,即使金额为NULL。在这种情况下,我们可以将总和除以计数:

SELECT
    title,
    SUM(amount) / COUNT(*) AS avglevel
FROM test
GROUP BY
    title;

Demo

答案 1 :(得分:1)

您可以在使用分母时尝试使用以下情况

SELECT title, 
(level1+level2+level3+level4)/(case when level1 is not null then 1 end+
case when level2 is not null then 1 end+case when level3 is not null then 1 end+case when level4 is not null then 1 end) as avglevel, 
level1, level2, level3, level4
FROM test

答案 2 :(得分:1)

您可以在单个表达式中执行此操作。 MySQL具有一些内置功能,这些功能使其变得更简单:

SELECT title, 
       (COALESCE(level1, 0) + COALESCE(level2, 0) + COALESCE(level3, 0) + COALESCE(level4, 0)
       ) /
       ( (level1 is not null) + (level2 is not null) +
         (level3 is not null) + (level4 is not null)
       ) as avglevel,
      level1, level2, level3, level4
FROM test;

答案 3 :(得分:0)

尝试以下情况,如下所示

 SELECT title, 
(IFNULL(level1,0)+IFNULL(level2,0)+IFNULL(level3,0)+IFNULL(level4,0))/
(4-(case when level1 is null then 1 else 0 end)-(case when level2 is null then 1 else 0 end)-
(case when level3 is null then 1 else 0 end)- (case when level4 is null then 1 else 0 end) ) as avglevel,
level1, level2, level3, level4
FROM test;