#sql #sum #pivot #aggregate-functions
#sql #сумма #сводная #агрегатные функции
Вопрос:
У меня есть одна таблица, my_table, с данными, подобными следующим:
---------------------------
|Accesses | Fruit | Level |
---------------------------
| 5 | Apple | 2 |
| 2 | Banana | 3 |
| 2 | Apple | 1 |
| 6 | Cherry | 4 |
| 12 | Apple | 4 |
| 9 | Banana | 1 |
| 1 | Durian | 2 |
---------------------------
Я пытаюсь написать запрос, который суммировал бы количество обращений к ГРУППЕ ПО фруктам и общее количество обращений к каждому фрукту, но только для обращений к уровням меньше 4. Результат для этого запроса будет:
---------------------------|--------------
|Fruit | FilteredAccesses | TotalAccesses |
--------------------------- ---------------
|Apple | 7 | 19 |
|Banana | 11 | 11 |
|Durian | 1 | 1 |
-------------------------------------------
Я попробовал следующее самосоединение, но не получил ожидаемых результатов:
SELECT A.Fruit, SUM(A.Accesses) AS FilteredAccesses, SUM(B.Accesses) As TotalAccesses
FROM my_table A, my_table B
WHERE (A.Fruit = B.Fruit) AND (A.Level < 4)
GROUP BY A.Fruit
Есть ли что-то, чего мне не хватает? Можно ли это сделать даже с помощью self join?
Комментарии:
1. Почему ‘cherry’ исключен из результатов?
2. Потому что меня интересуют записи, где уровень < 4.
Ответ №1:
Используйте условную агрегацию:
SELECT A.Fruit, SUM(CASE WHEN A.LEVEL < 4 THEN A.Accesses ELSE 0 END) AS FilteredAccesses,
SUM(A.Accesses) As TotalAccesses
FROM my_table A
GROUP BY A.Fruit
Комментарии:
1. Так что в этом случае строки, которые
A.Level < 4
не удовлетворяют, все равно будут включены в результаты? Думаю, я могORDER BY A.Fruit DESC
бы.2. Вы можете использовать
having
фильтр в конце запроса:having SUM(CASE WHEN A.LEVEL < 4 THEN A.Accesses ELSE 0 END) > 0
3. @AndrewSayer Похоже, это приводит к синтаксической ошибке:
SELECT A.Fruit, HAVING SUM(CASE WHEN A.LEVEL < 4 THEN A.Accesses ELSE 0 END) > 0 AS FilteredAccesses, SUM(A.Accesses) As TotalAccesses FROM my_table A GROUP BY A.Fruit
я что-то пропустил?4. Вы пропустили «в конце запроса».
SELECT A.Fruit, SUM(CASE WHEN A.LEVEL < 4 THEN A.Accesses ELSE 0 END) AS FilteredAccesses, SUM(A.Accesses) As TotalAccesses FROM my_table A GROUP BY A.Fruit having SUM(CASE WHEN A.LEVEL < 4 THEN A.Accesses ELSE 0 END) > 0
Ответ №2:
Нет необходимости в самосоединении. Вы можете сделать это в одном запросе агрегации. Хитрость заключается в том, чтобы использовать case
выражение on level
для вычисления «отфильтрованных» обращений, чтобы учитывались только строки, удовлетворяющие условиям.
select fruit,
sum(case when level < 4 then accesses else 0 end) filtered_accesses,
sum(accesses) total_accesses
from mytable
group by fruit
Этот метод называется условной агрегацией.
Комментарии:
1. Интересно. Можно ли не включать строки, которые не соответствуют
Level < 4
условию? В противном случае они включены из того, что я вижу.2. @HerbPowell: они включены в
total_accesses
, но не вfiltered_accesses
— вот как я понял ваш вопрос.