Перейти к основному содержимому
Версия: 7.0

Оператор PARTITION

Оператор PARTITION - создание свойства, реализующего разбиение / упорядочивание либо простое распределение.

Синтаксис

PARTITION 
type [expr1, ..., exprN]
[ORDER [DESC] orderExpr1, ..., orderExprK]
[TOP topExpr] [OFFSET offsetExpr]
[BY groupExpr1, ..., groupExprM]

Где type определяется как:

SUM
PREV
LAST
UNGROUP propertyId distributionType
CUSTOM [NULL] [className] aggrFunc

А distributionType определяется как:

PROPORTION [STRICT] ROUND(digits)
LIMIT [STRICT]

Описание

Оператор PARTITION создаёт свойство, которое для каждого набора объектов либо вычисляет агрегирующую функцию по окну разбиения (SUM, PREV, LAST, CUSTOM), либо распределяет некоторое значение среди наборов объектов группы (UNGROUP).

Блок BY описывает группы, на которые будет разбиваться множество наборов объектов. Если блок BY не указывается, то считается, что все наборы объектов входят в одну группу.

Блок ORDER определяет порядок, в котором будет либо вычисляться агрегирующая функция, либо проходить распределение. Если эта функция некоммутативна, заданный порядок должен быть однозначно определяемым. Если в выражениях, задающих порядок, объявляется новый параметр (не встречавшийся ранее в опциях PARTITION и BY и в верхнем контексте), то при вычислении результирующего значения автоматически добавляется условие на не-NULL всех этих выражений.

Блоки TOP и OFFSET ограничивают подмножество записей, отбираемых внутри каждого разбиения: сначала OFFSET пропускает начальные записи, затем берутся следующие TOP записей в заданном порядке. Любой из блоков может быть указан независимо.

Параметры

  • type

    Тип операции. Может принимать одно из значений: SUM, PREV, LAST, UNGROUP, CUSTOM.

  • propertyId

    Идентификатор распределяемого свойства. Значение этого свойства должно быть числового типа, а количество параметров должно совпадать с количеством группировок в блоке BY. На вход этому свойству передаются объекты, идентифицирующие группу.

  • distributionType

    Стратегия распределения. Одна из:

    • PROPORTION — пропорциональное распределение: значение propertyId делится среди наборов объектов группы пропорционально основному выражению и округляется до digits знаков после запятой.
    • LIMIT — распределение с лимитами: значение propertyId устанавливается для первого (в порядке ORDER) набора объектов до лимита, заданного основным выражением; остаток затем устанавливается для следующего набора и так далее. Лимиты задаются в тех же единицах, что и распределяемое значение.
  • STRICT

    Значение propertyId должно быть расписано точно (без остатка) по наборам объектов группы. Если в результате распределения остаётся остаток (для PROPORTION он может быть и отрицательным), он добавляется первому набору объектов в порядке ORDER для PROPORTION и последнему набору в порядке ORDER для LIMIT.

  • digits

    Целочисленный литерал, указывающий количество знаков после запятой при округлении в PROPORTION.

  • NULL

    Указывает, что агрегирующая функция может вернуть NULL, даже если все значения параметров — не-NULL.

  • className

    Имя встроенного класса значения, возвращаемого CUSTOM. Если опущено, класс результата выводится из первого основного выражения (либо из первого выражения ORDER, если основной список пуст).

  • aggrFunc

    Строковый литерал, содержащий имя пользовательской или встроенной в СУБД агрегирующей функции.

  • expr1, ..., exprN

    Основные выражения. Для SUM, PREV, LAST и UNGROUP список содержит ровно одно выражение: для SUM оно суммируется накопительно по окну разбиения; для PREV и LAST берётся со значения предыдущего и текущего набора соответственно (NULL для первого набора в случае PREV); для UNGROUP оно определяет пропорцию (с PROPORTION) или лимит (с LIMIT). При UNGROUP набор объектов, для которого значение этого выражения равно NULL, исключается из распределения — создаваемое свойство возвращает для него NULL — в отличие от набора со значением 0, который в распределении участвует. Остаток при STRICT также присваивается только среди участвующих наборов. Если участвовать должны все наборы, преобразуйте возможный NULL этого выражения в 0 (например, оператором OVERRIDE). Для CUSTOM список содержит операнды, передаваемые aggrFunc; список может быть пустым, но тогда блок ORDER обязателен.

  • groupExpr1, ..., groupExprM

    Список группировочных выражений.

  • DESC

    Ключевое слово. Указывает на обратный порядок просмотра наборов объектов.

  • orderExpr1, ..., orderExprK

    Список выражений, определяющих порядок, в котором будут просматриваться наборы объектов. Для определения порядка сначала используется значение первого выражения, затем при равенстве — значение второго и т. д.

  • TOP topExpr

    В каждом разбиении в вычислении будут участвовать только первые n записей в порядке разбиения, где n — значение выражения topExpr.

  • OFFSET offsetExpr

    В каждом разбиении первые m записей в порядке разбиения будут пропущены, где m — значение выражения offsetExpr.

Примеры

// определяет место команды в конференции
CLASS Conference;
conference = DATA Conference (Team);
points = DATA INTEGER (Team);
gamesWon = DATA INTEGER (Team);
place 'Место' (Team team) = PARTITION SUM 1 ORDER DESC points(team), gamesWon(team) BY conference(team);

// строим порядковые индексы объектов в базе по возрастанию их внутренних идентификаторов (то есть в порядке создания)
index 'Номер' (Object o) = PARTITION SUM 1 IF o IS Object ORDER o;

// находит команду, следующую в турнирной таблице по конференции
prevTeam (Team team) = PARTITION PREV team ORDER place(team), team BY conference(team);

// пример пропорционального распределения
CLASS Order;
transportSum 'Транспортные расходы' = DATA NUMERIC[10,2] (Order);

CLASS OrderDetail;
order = DATA Order (OrderDetail) NONULL DELETE;
sum = DATA NUMERIC[14,2] (OrderDetail);

// при transportSum, равном 100, и трех строках с sum 1, 1, 1 строки получат 33.34, 33.33 и 33.33
transportSum 'Транспортные расходы по строке' (OrderDetail d) = PARTITION UNGROUP transportSum
PROPORTION STRICT ROUND(2) sum(d)
ORDER d
BY order(d);

// пример распределения с лимитами
// при discountSum, равном 60, и строках с sum 100 и 300 первая строка в порядке ORDER получит 60, вторая — NULL;
// при discountSum, равном 500, строки получат 100 и 400 (300 по лимиту и остаток 100 из-за STRICT)
discountSum 'Скидка' = DATA NUMERIC[10,2] (Order);
discountSum 'Скидка по строке' (OrderDetail d) =
PARTITION UNGROUP discountSum
LIMIT STRICT sum(d)
ORDER sum(d), d
BY order(d);
;