Давайте посмотрим на мою вымышленную прогрессию заработной платы по сравнению с вымышленной подругой, которая выбрала другой путь карьеры (обратите внимание на повышение зарплаты в 2011 году):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
select 'Lukas' as employee, 'SoftSkills' as company, 80000 as salary, 2007 as year from dual union all select 'Lukas' , 'SoftSkills' , 80000, 2008 from dual union all select 'Lukas' , 'SmartSoft' , 90000, 2009 from dual union all select 'Lukas' , 'SmartSoft' , 95000, 2010 from dual union all select 'Lukas' , 'jOOQ' , 200000, 2011 from dual union all select 'Lukas' , 'jOOQ' , 250000, 2012 from dual union all select 'Tom' , 'SoftSkills' , 89000, 2007 from dual union all select 'Tom' , 'SoftSkills' , 90000, 2008 from dual union all select 'Tom' , 'SoftSkills' , 91000, 2009 from dual union all select 'Tom' , 'SmartSoft' , 92000, 2010 from dual union all select 'Tom' , 'SmartSoft' , 93000, 2011 from dual union all select 'Tom' , 'SmartSoft' , 94000, 2012 from dual |
Теперь мы привыкли собирать статистику с помощью простой группировки и простых агрегатных функций. Например, давайте посчитаем, сколько Лукас и Том заработали в среднем за последние несколько лет:
1
2
3
4
5
6
7
|
with data as ([above select ]) select employee, avg (salary) from data group by employee |
Это покажет, что Лукас заработал больше:
+ -------- + ----------- + | СОТРУДНИК | AVG (ЗАРПЛАТА) | + -------- + ----------- + | Лукас | 132500 | Том | 91500 | + -------- + ----------- +
Так что, наверное, интересно узнать, что они в среднем заработали в какой компании:
1
2
3
4
5
6
7
8
9
|
with data as (...) select company, employee, avg (salary) from data group by company, employee order by company, employee |
И сразу становится ясно, где большие деньги, и что Том принял плохое решение.
+ ---------- + -------- + ----------- + | КОМПАНИЯ | СОТРУДНИКИ | AVG (SALARY) | + ---------- + -------- + ----------- + | JOOQ | Лукас | 225000 | | СмартСофт | Лукас | 92500 | | SmartSoft | Том | 93000 | | SoftSkills | Лукас | 80000 | | SoftSkills | Том | 90000 | + ---------- + -------- + ----------- +
СВЕРНУТЬ
Добавляя поля группировки, мы «теряем» некоторую информацию об агрегации. В приведенных выше примерах общая средняя заработная плата на одного работника больше не доступна непосредственно из результата. Это очевидно, учитывая алгоритм группировки. Но в красивых отчетах мы часто хотим отображать и заголовки групп. Здесь вступают в игру ROLLUP, CUBE (и GROUPING SETS). Рассмотрим следующий запрос:
1
2
3
4
5
6
7
|
with data as (...) select company, employee, avg (salary) from data group by rollup (company), employee |
Приведенная выше функция свертки теперь добавит дополнительные строки в набор результатов группировки, содержащие полезные агрегированные значения. В этом случае, когда мы «свернем зарплату компании», мы получим среднее значение оставшихся полей группировки, то есть среднее значение на одного сотрудника:
+ ---------- + -------- + ----------- + | КОМПАНИЯ | СОТРУДНИКИ | AVG (SALARY) | + ---------- + -------- + ----------- + | SmartSoft | Том | 93000 | | SoftSkills | Том | 90000 | | {ноль} | Том | 91500 | | JOOQ | Лукас | 225000 | | СмартСофт | Лукас | 92500 | | SoftSkills | Лукас | 80000 | | {null} | Лукас | 132500 | + ---------- + -------- + ----------- +
Обратите внимание, что эти строки содержат ту же информацию, что и в первом запросе, где мы группировали только по сотруднику … Это становится еще интереснее, когда мы добавляем больше группирующих полей в функцию свертки:
1
2
3
4
5
6
7
|
with data as (...) select company, employee, avg (salary) from data group by rollup (employee, company) |
Как видите, порядок группировки полей важен в функции свертки. Результат этого запроса теперь также добавляет общую среднюю зарплату, выплачиваемую всем сотрудникам во всех компаниях.
+ ---------- + -------- + ----------- + | КОМПАНИЯ | СОТРУДНИКИ | AVG (SALARY) | + ---------- + -------- + ----------- + | SmartSoft | Том | 93000 | | SoftSkills | Том | 90000 | | {ноль} | Том | 91500 | | JOOQ | Лукас | 225000 | | СмартСофт | Лукас | 92500 | | SoftSkills | Лукас | 80000 | | {null} | Лукас | 132500 | | {ноль} | {нуль} | 112000 | + ---------- + -------- + ----------- +
Чтобы идентифицировать строки итогов для отчетов, вы можете использовать функцию GROUPING () в DB2, Oracle, SQL Server и Sybase SQL Anywhere. В Oracle и SQL Server есть еще более полезная функция GROUPING_ID ():
1
2
3
4
5
6
7
|
with data as (...) select grouping_id(employee, company) id, company, employee, avg (salary) from data group by rollup (employee, company) |
Он документирует, на каком «уровне группировки» функции свертки была создана текущая строка:
+ ---- + ---------- + -------- + ----------- + | ID | КОМПАНИЯ | СОТРУДНИКИ | AVG (SALARY) | + ---- + ---------- + -------- + ----------- + | 0 | СмартСофт | Том | 93000 | | 0 | SoftSkills | Том | 90000 | | 1 | {null} | Том | 91500 | | 0 | jOOQ | Лукас | 225000 | | 0 | СмартСофт | Лукас | 92500 | | 0 | SoftSkills | Лукас | 80000 | | 1 | {null} | Лукас | 132500 | | 3 | {null} | {null} | 112000 | + ---- + ---------- + -------- + ----------- +
CUBE
Функция куба работает аналогично, за исключением того, что порядок полей группировки куба становится неактуальным, так как все комбинации группировки объединяются. Это немного сложно выразить словами, поэтому давайте запустим это:
1 2 3 4 5 6 7 | with data as (...) select grouping_id(employee, company) id, company, employee, avg (salary) from data group by cube (employee, company) |
В следующем результате вы получите:
- GROUPING_ID () = 0: в среднем по компании и сотруднику. Это нормальный результат группировки
- GROUPING_ID () = 1: в среднем на сотрудника
- GROUPING_ID () = 2: в среднем по компании
- GROUPING_ID () = 3: общее среднее
+ ---- + ---------- + -------- + ----------- + | ID | КОМПАНИЯ | СОТРУДНИКИ | AVG (SALARY) | + ---- + ---------- + -------- + ----------- + | 3 | {null} | {null} | 112000 | | 2 | jOOQ | {null} | 225000 | | 2 | SmartSoft | {null} | 92800 | | 2 | SoftSkills | {null} | 86000 | | 1 | {null} | Том | 91500 | | 0 | СмартСофт | Том | 93000 | | 0 | SoftSkills | Том | 90000 | | 1 | {null} | Лукас | 132500 | | 0 | jOOQ | Лукас | 225000 | | 0 | СмартСофт | Лукас | 92500 | | 0 | SoftSkills | Лукас | 80000 | + ---- + ---------- + -------- + ----------- +
Другими словами, используя функцию CUBE (), вы получите результаты группировки для каждой возможной комбинации полей группировки, переданных в функцию CUBE (), что приведет к 2 ^ n GROUPING_ID () для n «кубированных» полей группировки
Поддержка в JOOQ
В jOOQ 2.0 появилась поддержка этих функций. Если вы хотите перевести последний выбор в jOOQ, вы получите примерно такой код Java:
01
02
03
04
05
06
07
08
09
10
11
|
// assuming that DATA is an actual table... create.select( groupingId(DATA.EMPLOYEE, DATA.COMPANY).as( "id" ), DATA.COMPANY, DATA.EMPLOYEE, avg(SALARY)) .from(DATA) .groupBy(cube(DATA.EMPLOYEE, DATA.COMPANY)); |
С этим мощным инструментом вы готовы ко всем этим модным отчетам и обзорам данных. Для получения более подробной информации читайте о функциях ROLLUP (), CUBE () и GROUPING SETS () на странице документации по SQL Server, которая довольно хорошо объясняет это:
http://msdn.microsoft.com/en-us/library/bb522495.aspx
Ссылка: GROUP BY ROLLUP / CUBE от нашего партнера по JCG Лукаса Эдера из блога JAVA, SQL и JOOQ .
Статьи по Теме :