Среднее из 4 столбцов со случайными нулевыми значениями - PullRequest
0 голосов
/ 14 февраля 2019

У меня есть таблица сотрудников с 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. Странные значения NULL аномалии MySQL AVG ()

Ответы [ 4 ]

0 голосов
/ 14 февраля 2019

Вы можете сделать это в одном выражении.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;
0 голосов
/ 14 февраля 2019

попробуйте, как показано ниже, используя случай, когда

 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;
0 голосов
/ 14 февраля 2019

В связи с вашим текущим дизайном таблицы вам нужно выполнять операции агрегирования над столбцами , а не строками.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;

Демо

Функция AVG уже будет игнорировать значения NULLпо умолчанию, поэтому сумма будет нормализована по количеству записей, которое не включает в себя записи, имеющие NULL.

Редактировать:

После настройки демонстрацииКажется, вы do хотите нормализовать среднее значение, используя все уровни, даже если сумма будет NULL.В этом случае мы можем взять сумму, деленную на количество:

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

Демо

0 голосов
/ 14 февраля 2019

Вы можете попробовать ниже, используя случай, когда для вас знаменатель

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...