Операции с множествам и
Одной из ключевых возможностей платформы является возможность выполнения некоторых операций для всех наборов объектов, для которых значения одного или нескольких свойств не равны NULL
. В логике свойств такой операцией является вычисление различных агрегирующих функций.
Агрегирующие функции
Агрегируюшая функция вычисляет на множестве наборов объектов некоторый результат в виде единичного объекта. Эта функция определяется начальным значением (как правило NULL
), свойствами, которые она использует (операндами), операцией добавления к промежуточному результату текущих значений операндов, а также функцией преобразования промежуточного результата в конечный (как правило промежуточный результат и является конечным результатом).
Агрегирующая функция является коммутативной, если при вычислении результата не важно, в каком порядке перебираются наборы объектов исходного множества.
В таблице снизу представлены поддерживаемые на данный момент виды агрегирующих функций:
Вид / опция в инструкции | Начальное значение | Назв. операндов | Операция добавления | Функция преобразования | Коммутативность | Тип данных |
---|---|---|---|---|---|---|
SUM | NULL | operand | result = result (+) operand | result | + | число |
MAX | NULL | operand | result = max(result, operand) | result | + | любой сравнимый |
MIN | NULL | operand | result = min(result, operand) | result | + | любой сравнимый |
CONCAT | NULL | separator, operand | result = CONCAT separator, result, operand | result | - | строковый |
LAST / PREV | NULL | where, operand | result = IF where THEN operand ELSE result | result | - | любой |
С точки зрения определения множества наборов объектов, а также способа представления результата, можно выделить четыре основных оператора работы с множествами:
- Группировка (
GROUP
) - Разбиение / Упорядочивание (
PARTITION ... ORDER
) - Рекурсия (
RECURSION
) - Распределение (
UNGROUP
)
Корректность операции
Необходимо учитывать, что при выполнении каждой операции над множеством наборов объектов это множество должно быть конечным. В этом случае операцию будем называть корректной.
Примеры
CLASS A;
d = DATA INTEGER (A);
f (b) = GROUP SUM 1 IF d(a) < b;
messageF { MESSAGE f(5); } // успешно выполнится
g = GROUP SUM f(b);
messageG { MESSAGE g(); } // f(b) не NULL для бесконечного числа b, платформа выдаст ошибку
FORM f
OBJECTS d=DATE
;
printFWithD { PRINT f OBJECTS d=currentDate(); } // успешно выполнится
// фильтра для дат нет, а d IS DATE не NULL для бесконечного числа d, платформа выдаст ошибку
printFWithoutD { PRINT f; }
Существует несколько нетривиальных случаев, когда операция является корректной, но платформа не может это определить. Например, если единственным ограничивающим условием на параметр является вхождение его в диапазон:
hs = GROUP SUM 1 IF (a AS INTEGER) >= 4 AND a <= 6;
messageHS { MESSAGE hs(); } // теоретически должна выдать 3, но платформа все равно выдаст ошибку
// workaround: для работы с интервалами можно использовать свойство iterate
// (оно в свою очередь реализуется через рекурсию)
hi = GROUP SUM 1 IF iterate(a, 4, 6);