Оператор GROUP
Оператор GROUP - создание свойства, реализующего группировку.
Синтаксис
GROUP
type [expr1, ..., exprN]
[orderClause]
[TOP topExpr [OFFSET offsetExpr]]
[WHERE whereExpr]
[BY groupExpr1, ..., groupExprM]
Подправило type, которое используется сразу после GROUP, имеет следующий синтаксис:
SUM | MAX | MIN | AGGR | NAGGR | EQUAL | CONCAT | LAST | CUSTOM [NULL] [className] aggrFunc
Подправило orderClause, которое используется после списка агрегируемых выражений, имеет следующий синтаксис:
[WITHIN] ORDER [DESC] orderExpr1, ..., orderExprK
Здесь type задает вид агрегирующей функции, а orderClause задает форму упорядочивания: обычный ORDER ... либо WITHIN ORDER ... для ordered-set CUSTOM-агрегатов.
Описание
Оператор GROUP создает свойство, реализующее группировку. Тип группировки определяется видом агрегирующей функции. Этот оператор отличается от других тем, что может неявно объявлять свои параметры в используемых выражениях (по аналогии с инструкцией =, когда параметры не заданы явно). При этом, важно понимать, что эти "неявно объявленные" параметры не являются параметрами создаваемого свойства (которые на самом деле определяются блоком BY и/или использованными верхними параметрами)
Блок BY описывает группировочные выражения. Каждое выражение соответствует параметру, создаваемого свойства. Как и в остальных операторах, в этом операторе разрешено использовать верхние параметры, причем использованные параметры также неявно являются группировками создаваемого свойства. Если блок BY не задан и верхние параметры не используются, все подходящие наборы объектов образуют одну группу, а создаваемое свойство не имеет параметров. Соответственно, при использовании оператора в инструкции = и явном задании в этой инструкции параметров слева, выражения из блока BY отображаются только на неиспользованные параметры. При этом, если классы или количество этих параметров будет не соответствовать количеству / классам выражений BY, платформа выдаст ошибку.
Если блок BY задан, этот оператор нельзя использовать внутри выражений.
Блок ORDER определяет порядок, в котором будет вычисляться агрегирующая функция. Для CONCAT и LAST он обязателен. Для коммутативных агрегаторов (SUM, MAX, MIN, EQUAL, AGGR, NAGGR) он может быть задан дополнительно; в этом случае порядок не меняет итоговое значение сам по себе, но влияет на то, какие записи попадут в агрегирование при использовании TOP / OFFSET. Если функция некоммутативна, порядок следует задавать так, чтобы он был однозначно определяемым. Если в выражениях, задающих порядок, объявляется новый параметр (не использующийся в остальных блоках и в верхнем контексте), то при вычислении результирующего значения автоматически добавляется условие на не NULL всех этих выражений.
Для CUSTOM-агрегатов ключевое слово WITHIN не задает какой-то отдельный "дополнительный порядок", а выбирает форму SQL-вызова пользовательской / встроенной агрегатной функции. Без WITHIN порядок передается внутрь самого вызова функции, то есть конструкция вида GROUP CUSTOM ... 'aggrFunc' expr1, ..., exprN ORDER orderExpr1, ... соответствует вызову aggrFunc(expr1, ..., exprN ORDER BY orderExpr1, ...). С WITHIN используется ordered-set форма, то есть GROUP CUSTOM ... 'aggrFunc' expr1, ..., exprN WITHIN ORDER orderExpr1, ... соответствует вызову aggrFunc(expr1, ..., exprN) WITHIN GROUP (ORDER BY orderExpr1, ...). Это важно для агрегатов, которые в СУБД определены именно через WITHIN GROUP, например percentile_cont.
С точки зрения результата различие в том, какие именно значения считаются "входом" агрегата. Без WITHIN агрегат вычисляет результат по значениям expr1, ..., exprN, а ORDER только задает порядок их обработки. С WITHIN результат вычисляется по упорядоченному набору значений из ORDER: именно они образуют выборку, по которой считается агрегат, а expr1, ..., exprN становятся параметрами самой агрегатной функции. Например, в GROUP CUSTOM ... 'percentile_cont' 0.9 WITHIN ORDER value(i) выражение 0.9 задает, какой процентиль нужен, а результатом будет 90-й процентиль значений value(i) внутри группы.
Блок TOP и его опциональное продолжение OFFSET ограничивают множество записей, уже отобранных для агрегирования внутри каждой группы: сначала применяется смещение OFFSET, затем берутся следующие TOP записей в заданном порядке. Блок OFFSET отдельно без TOP не используется. Если блок ORDER не задан, выбор этих записей происходит в произвольном порядке.
Блок WHERE определяет условие, при выполнении которого наборы объектов будут участвовать в операции группировки. Его можно задавать только для агрегирующих функций AGGR, NAGGR, CONCAT, LAST. Для LAST, если WHERE не задан, в качестве условия используется не NULL-ность самого агрегируемого выражения.
Для AGGR, NAGGR использовать этот блок явно (а не, скажем, оператор IF в блоках GROUP и BY) имеет смысл, только с точки зрения возможности изменения создаваемого свойства на не NULL в некоторых автоматических механизмах платформы (например, в автоматическом разрешении простых ограничений).
Параметры
-
typeТип агрегирующей функции. Может иметь одно из следующих встроенных значений:
SUM,MAX,MIN,CONCAT,EQUAL,AGGR,NAGGR,LAST, либо формуCUSTOM [NULL] [className] aggrFunc. -
NULLКлючевое слово. Используется только для
CUSTOM-агрегатов и указывает, что агрегат может возвращатьNULL, даже если все значения параметров не равныNULL. -
classNameИмя встроенного класса возвращаемого значения. Используется только для
CUSTOM-агрегатов и позволяет явно задать тип результата. Если не задан, тип результата выводится из основного выражения агрегата: обычно из первого основного операнда, а для формы сWITHINи для формы без основных операндов - из первого выражения вORDER. -
aggrFuncСтроковый литерал с именем пользовательской или встроенной в СУБД агрегатной функции. Используется только для
CUSTOM-агрегатов. -
expr1, ..., exprNСписок выражений, значения которых идут на вход агрегирующей функции в качестве операндов. Количество выражений должно соответствовать количеству операндов используемой функции. Для
SUM,MAX,MIN,EQUAL,AGGR,NAGGRподдерживается одно выражение. ДляSUMэто выражение должно иметь числовой класс семействаIntegralClass(например,INTEGER,LONG,NUMERIC,DOUBLE). ДляAGGRиNAGGRоперандом должен быть простой объектный параметр, а не произвольное выражение. ДляCONCATподдерживаются либо два выражения: агрегируемое значение и разделитель, либо одно выражение JSON / JSONTEXT-типа. ДляLASTуказывается одно выражение, а условие отбора задается черезWHEREлибо выводится автоматически из неNULL-ности этого выражения. ДляCUSTOM-агрегатов список может быть пустым, но тогда блокORDER/WITHIN ORDERобязателен. -
groupExpr1, ..., groupExprMСписок группировочных выражений (группировок). Если список не задан и верхние параметры не используются, все подходящие наборы объектов образуют одну группу.
-
WITHINКлючевое слово. Используется только для
CUSTOM-агрегатов и задает ordered-set форму вызова агрегатной функции. БезWITHINвыражения изORDERпередаются внутрь вызова агрегата:aggrFunc(... ORDER BY ...). СWITHINони выносятся в отдельную часть SQL-вызова:aggrFunc(...) WITHIN GROUP (ORDER BY ...). С функциональной точки зрения это означает, что безWITHINагрегат работает по значениям основных выражений, а сWITHIN- по упорядоченным значениям изORDER, тогда как основные выражения становятся параметрами самой функции. Для остальных типов не применяется. -
DESCКлючевое слово. Указывает на обратный порядок просмотра наборов объектов.
-
orderExpr1, ..., orderExprKСписок выражений, определяющих порядок, в котором будут просматриваться наборы объектов при вычислении агрегирующей функции. Для определения порядка сначала используется значение первого выражения, затем при равенстве используется значение второго и т.д. Для
CONCATиLASTэтот список обязателен. ДляCUSTOM-агрегатов он обязателен, если список основных выражений не задан. -
TOP topExprВ агрегировании внутри каждой группы будут участвовать только первые
nзаписей, гдеn- значение выраженияtopExpr. -
OFFSET offsetExprОпциональное продолжение блока
TOP. В агрегировании внутри каждой группы будут участвовать только записи, начиная со смещенияm, гдеm- значение выраженияoffsetExpr. -
whereExprФильтрующее выражение. В группировке будут участвовать только те наборы объектов, для которых значение фильтрующего выражения не равно
NULL.
Примеры
CLASS Game;
CLASS Team;
hostGoals = DATA INTEGER (Game);
hostTeam = DATA Team (Game);
date = DATA DATE (Game);
hostGoalsScored(team) = GROUP SUM hostGoals(Game game) BY hostTeam(game);
last3HostGoalsScored(team) = GROUP SUM hostGoals(Game game) ORDER DESC date(game), game TOP 3 BY hostTeam(game);
name = DATA STRING[100] (Country);
// получается свойство (STRING[100]) -> Country
countryName = GROUP AGGR Country country BY name(country);
CLASS Book;
CLASS Tag;
name = DATA STRING[100] (Tag);
in = DATA BOOLEAN (Book, Tag);
tags(Book b) = GROUP CONCAT name(Tag t) IF in(b, t), ', ' ORDER name(t), t TOP 10 OFFSET 0;
value = DATA NUMERIC[14,2] (INTEGER);
// 90-й процентиль значений value(i)
percentile90() = GROUP CUSTOM NUMERIC[14,2] 'percentile_cont' 0.9 WITHIN ORDER value(INTEGER i);