Skip to content

Два способа создания итогов в SQL

Пересказ статьи Steve Sohcot. Two Ways To Create Totals In SQL


При представлении табличных данных вам может потребоваться строка "итого" внизу списка.

Помнится лет 25! назад я применял подход создания многомерного массива для суммирования значений строка за строкой и столбец за столбцом. Как на стороне сервера, так и на JavaScript.

Создание итоговой строки на SQL (на стороне сервера) является более эффективным. Это также облегчает работу фронтенд разработчику.
Для начала давайте предположим, что у нас есть подобный пример запроса:

SELECT agent, SUM(hours) AS totalHours
FROM myTable
GROUP BY agent
ORDER BY agent

Результаты:



Метод 1: создание итогов с помощью UNION ALL


Первый подход, о котором я буду говорить, фактически создает копию вашего набора данных:

  • В этой копии отсутствует первый столбец, в котором выводятся различные значения.

  • Жестко кодируется слово "Total", чтобы совпадало число столбцов в каждом наборе данных

  • Объединяем два набора данных посредством UNION ALL.

  • Оборачиваем оба набора в оператор SELECT.

Не забудьте удалить ORDER BY из подзапросов.

SELECT
agent, SUM(totalHours) AS totalHours

FROM (
-- Исходный запрос
SELECT agent, SUM(hours) AS totalHours
FROM myTable
GROUP BY agent
UNION ALL
-- Копируем, но не показываем (или GROUP BY) первый столбец
-- вместо этого жестко кодируем слово "Total"
SELECT 'Total', SUM(hours) AS totalHours
FROM myTable
) AS qryMain
GROUP BY
agent
ORDER BY
agent

Теперь у нас есть строка "Итого", но она не является последней строкой набора данных:


"Total" - не последняя строка

Мы можем исправить это, изменив предложение ORDER BY с использованием предложения CASE:

SELECT
agent, SUM(totalHours) AS totalHours

FROM (
-- Исходный запрос
SELECT agent, SUM(hours) AS totalHours
FROM myTable
GROUP BY agent
UNION ALL
-- Копируем, но не показываем (или GROUP BY) первый столбец
-- вместо этого жестко кодируем слово "Total"
SELECT 'Total', SUM(hours) AS totalHours
FROM myTable
) AS qryMain
GROUP BY
agent
ORDER BY
CASE
WHEN agent = 'Total' THEN 1
ELSE 0
END,
agent

Обратите внимание на оператор CASE в ORDER BY

Объяснение: Когда столбец содержит “Total”, то это дает значение 1, для всех остальных записей - значение 0. Следовательно, итоги всегда будут находиться в конце при сортировке по возрастанию. Вторичная сортировка использует другое поле (здесь “agent”).

Теперь мы имеем тоги в конце:


“Total” является последней строкой, как и должно быть

Метод 2: создание итогов при помощи ROLLUP


Этот метод может быть специфичен для используемой версии SQL. Это работает в MS SQL Server

Вы можете просто добавить функцию ROLLUP сразу после GROUP BY.

Не забудьте скобки


SELECT agent, SUM(hours) AS totalHours
FROM myTable
GROUP BY
ROLLUP (agent)

Это работает, но вы увидите значение NULL:


Итоги обозначаются как NULL

Опять таки, чтобы облегчить жизнь фронтэтд-разработчику, мы можем заменить NULL на "Total".

Просто заменить будет недостаточно, необходимо использовать ранее упомянутый "сортировочный" трюк:

SELECT ISNULL(agent,'Total') AS agent, SUM(hours) AS totalHours
FROM myTable
GROUP BY
ROLLUP (agent)
ORDER BY
CASE
WHEN ISNULL(agent, 'Total') = 'Total' THEN 1
ELSE 0
END,
ISNULL(agent,'Total')

Обратите внимание, что я заменяю NULL на "Total" в нескольких местах.

Последний трюк с итогами SQL


Мне часто требуется иметь "Total" последней строкой. Иногда у меня будет значение "Other", которое я хотел бы иметь предпоследней строкой (вместо вывода в алфавитном порядке). И тут оператор CASE в предложении ORDER BY поможет решить эту задачу:

SELECT ISNULL(agent,'Total') AS agent, SUM(hours) AS totalHours
FROM myTable
GROUP BY
ROLLUP (agent)
ORDER BY
CASE
WHEN ISNULL(agent, 'Total') = 'Other' THEN 1
WHEN ISNULL(agent, 'Total') = 'Total' THEN 9
ELSE 0
END,
ISNULL(agent,'Total')



Ссылки по теме
1. Разница между Cube и Rollup
2. Получение итоговых данных с помощью оператора ROLLUP
Категории: T-SQL

Обратные ссылки

Нет обратных ссылок

Комментарии

Показывать комментарии Как список | Древовидной структурой

Нет комментариев.

Автор не разрешил комментировать эту запись

Добавить комментарий

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Добавленные комментарии должны будут пройти модерацию прежде, чем будут показаны.