Опубликован: 20.12.2010 | Уровень: специалист | Доступ: свободно
Лекция 16:

SQL в хранилищах данных: агрегация и суммирование

Использование CUBE для вычисления частичных сумм

Использование CUBE для вычисления частичных сумм аналогично использованию предложения ROLLUP для вычисления частичных сумм, в котором можно ограничить использование некоторых измерений. В этом случае вычисления всех возможных комбинаций ограничиваются указанными в списке группировки измерениями.

Синтаксис:

GROUP BY expr1, CUBE(expr2, expr3);

В результате выполнения этой команды будет вычислено 4 частичные суммы:

  • (expr1, expr2, expr3)
  • (expr1, expr2)
  • (expr1, expr3)
  • (expr1)

Пример 22.6. Пусть руководству компании требуется перекрестный отчет о прибыли по всем регионам по всем отделам продаж за 2007-2008 гг. без вывода частичных сумм. Предложение SELECT для приведенной на рис. 22.3 схемы ХД может выглядеть следующим образом:

SELECT Time, Region, Department, SUM(Profit) AS Profit FROM sales
   GROUP BY Time CUBE(Region, Department);

Вывод 4. Использование CUBE для вычислений частичных сумм

Time Region Department Profit
2007 Центральный VideoRental 75,00
2007 Центральный VideoSales 74,00
2007 Центральный NULL 149,00
2007 Восточный VideoRental 89,00
2007 Восточный VideoSales 115,00
2007 Восточный NULL 204,00
2007 Западный VideoRental 87,00
2007 Западный VideoSales 86,00
2007 Западный NULL 173,00
2007 NULL VideoRental 251,00
2007 NULL VideoSales 275,00
2007 NULL NULL 526,00
2008 Центральный VideoRental 82,00
2008 Центральный VideoSales 85,00
2008 Центральный NULL 167,00
2008 Восточный VideoRental 101,00
2008 Восточный VideoSales 137,00
2008 Восточный NULL 238,00
2008 Западный VideoRental 96,00
2008 Западный VideoSales 97,00
2008 Западный NULL 193,00
2008 NULL VideoRental 279,00
2008 NULL VideoSales 319,00
2008 NULL NULL 598,00

Без использования предложения CUBE для n -мерного куба потребуется 2n команд SELECT с UNION ALL.

Предложение CUBE целесообразно использовать при решении задач создания перекрестных отчетов.

Квалификатор DISTINCT имеет ошибочную семантику в предложениях ROLLUP и CUBE. Не рекомендуется применять квалификатор DISTINCT в комбинации с этими предложениями.

Функция GROUPING

Две проблемы возникают при использовании ROLLUP и CUBE. Первая: как можно программно определить, какие строки результирующего множества являются частичными суммами, и как найти точный уровень агрегации данной частичной суммы? Часто необходимо использовать частичные суммы для вычислений процентных отношений между суммами, поэтому нужен простой способ находить частичные суммы. Вторая проблема: что произойдет, если результат запроса содержит и NULL-значение хранимых строк, и псевдо-NULL-значения, созданные ROLLUP или CUBE? Как различить их в результирующем множестве?

Для решения этой задачи предназначена функция GROUPING. Это статистическая функция, выдающая дополнительный столбец, который содержит значение 1, если строка добавлена с помощью оператора CUBE или ROLLUP, или значение 0 — в ином случае.

Синтаксис (указывается в списке предложения SELECT ):

SELECT ...  [GROUPING(column_name)...]  ... 
  GROUP BY ...    {CUBE | ROLLUP}  (column_name)

Пример 22.7. Использование функции GROUPING для создания колонок-масок в результирующем множестве.

SELECT Time, Region, Department, SUM(Profit) AS Profit,
  GROUPING (Time) as T, 
  GROUPING (Region) as R, 
  GROUPING (Department) as D
  FROM Sales
GROUP BY ROLLUP (Time, Region, Department);

Вывод 5. Использование функции GROUPING

Time Region Department Profit Т R D
2007 Центральный VideoRental 75,00 0 0 0
2007 Центральный VideoSales 74,00 0 0 0
2007 Центральный NULL 149,00 0 0 1
2007 Восточный VideoRental 89,00 0 0 0
2007 Восточный VideoSales 115,00 0 0 0
2007 Восточный NULL 204,00 0 0 1
2007 Западный VideoRental 87,00 0 0 0
2007 Западный VideoSales 86,00 0 0 0
2007 Западный NULL 173,00 0 0 1
2007 NULL NULL 526,00 0 1 1
2008 Центральный VideoRental 82,00 0 0 0
2008 Центральный VideoSales 85,00 0 0 0
2008 Центральный NULL 167,00 0 0 1
2008 Восточный VideoRental 101,00 0 0 0
2008 Восточный VideoSales 137,00 0 0 0
2008 Восточный NULL 238,00 0 0 1
2008 Западный VideoRental 96,00 0 0 0
2008 Западный VideoSales 97,00 0 0 0
2008 Западный NULL 193,00 0 0 1
2008 NULL NULL 598,000 0 1 1
NULL NULL NULL 1124,00 1 1 1

Как видно из примера, маска "0 0 0" — агрегированная строка из таблицы, "0 0 1" — первый уровень агрегации, "0 1 1" — второй уровень агрегации, "1 1 1" — итоговая сумма.

Пример 22.8. Предположим, что оператор SELECT выдает следующее результирующее множество, созданное выражением CUBE.

Вывод 6.

Time Region Profit
2007 Восточный 200,00
2007 NULL 200,00
NULL Восточный 200,00
NULL NULL 190,00
NULL NULL 190,00
NULL NULL 190,00
NULL NULL 390,00

В результирующем множестве 4 различных строки с NULL-значениями для колонок "Время" (Time) и "Регион" (Region). Некоторые из этих NULL-значений должны представлять агрегаты CUBE, а некоторые — агрегаты NULL-значений из базы данных. Как отличить в отчете агрегатные NULL-значения, построенные предложением CUBE, от хранимых в БД NULL-значений?

Использование GROUPING-функции в комбинации с CASE -выражением и функцией преобразования типов данных CAST (expression AS data_type [ (length ) ]) позволяет решить эту проблему.

Выражение CASE выполняет оценку списка условий и возвращает одно из нескольких возможных выражений результатов.

Синтаксис:

CASE input_expression 
     WHEN when_expression THEN result_expression [ ...n ] 
     [ ELSE else_result_expression ] 
END

или

CASE
     WHEN Boolean_expression THEN result_expression [ ...n ] 
     [ ELSE else_result_expression ] 
END

Теперь можно преобразовать отчет из примера 22.8 таким образом, чтобы выделить агрегаты предложения CUBE, как показано ниже.

Пример 22.9. Разграничение агрегатных и хранимых NULL-значений.

SELECT 
CASE WHEN GROUPING(Time) = 1 THEN 'All Times' ELSE CAST(Time as CHAR(20)) END AS Time,
CASE WHEN GROUPING(Region) = 1 THEN 'All Regions' ELSE Region END AS Region, SUM(Profit) AS Profit
FROM Sales
GROUP BY CUBE(Time, Region);

Вывод 7. Разграничение агрегатных и хранимых NULL-значений

Time Region Profit
2007 Восточный 200,00
2007 All Regions 200,00
All Times Восточный 200,00
NULL NULL 190,00
NULL All Regions 190,00
All Times NULL 190,00
All Times All Regions 390,00

Первая колонка есть "Время" (Time), определенное выражением

CASE WHEN GROUPING(Time) = 1 THEN 'All Times' ELSE CAST(Time as CHAR(20)) END AS Time,

Значение Time определяется выражением CASE, содержащим функцию GROUPING. Функция GROUPING возвращает 1, если строка есть агрегат предложений ROLLUP или CUBE, иначе — 0. CASE работает с результатом функции GROUPING. Оно возвращает текст "All Times", если это 1, и значение колонки "Время" (time) из БД, если это 0. Значениями из базы данных будут либо фактическое значение, такое как 2007, или сохраняемое NULL-значение. Функция CAST используется для согласования типов, поскольку в результирующем множестве все колонки должны быть одного типа. Вторая колонка спецификации, показывающая значения колонки "Регион" (Region), обрабатывается аналогичным образом.

Функция GROUPING полезна не только для идентификации NULL-значений, она также может помочь отсортировать строки частичных сумм и отфильтровать результирующее множество. В примере ниже выбирается подмножество частичных сумм, созданное CUBE. Предложение HAVING ограничивает колонки, которые используются в функции GROUPING.

Пример 22.10.

SELECT Time, Region, Department, SUM(Profit) AS Profit, 
  GROUPING (Time) AS T,
  GROUPING (Region) AS R, 
  GROUPING (Department) AS D
  FROM Sales
  GROUP BY CUBE (Time, Region, Department)
  HAVING (GROUPING(Department)=1 AND GROUPING(Region)=1 AND GROUPING(Time)=1) 
  OR (GROUPING(Region)=1 AND (GROUPING(Department)=1)
  OR (GROUPING(Time)=1 AND GROUPING(department)=1);

Вывод 8. Пример использования функции GROUPING для фильтрации результата в частичных суммах и итоговой сумме

Time Region Department Profit
2007 NULL NULL 526,00
2008 NULL NULL 598,00
NULL Центральный NULL 316,00
NULL Восточный NULL 442,00
NULL Западный NULL 366,00
NULL NULL NULL 1124,00
Владислав Нагорный
Владислав Нагорный

Подскажите, пожалуйста, планируете ли вы возобновление программ высшего образования? Если да, есть ли какие-то примерные сроки?

Спасибо!

Лариса Парфенова
Лариса Парфенова

1) Можно ли экстерном получить второе высшее образование "Программная инженерия" ?

2) Трудоустраиваете ли Вы выпускников?

3) Можно ли с Вашим дипломом поступить в аспирантуру?