Оператор FORMULA
Оператор FORMULA - создание свойства, реализующего пользовательскую формулу.
Синтаксис
FORMULA [NULL] [className [valueId]] implList [( paramList )] [NULL]
Где implList определяется как:
[syntaxType1] text1, ..., [syntaxTypeN] textN
А paramList определяется как:
classId1 [paramId1], ..., classIdK [paramIdK]
Описание
Оператор FORMULA создает свойство, выполняющее произвольную формулу на языке SQL. При этом есть возможность задать формулу отдельно для различных диалектов SQL, для того, чтобы эти свойства были переносимы между различными СУБД.
FORMULA — контекстно-независимый оператор-свойство: он не может стоять внутри выражений. Использовать его можно в правой части =-объявления или анонимно внутри скобок в применении оператора JOIN.
Что именно создаёт оператор — результирующий класс по умолчанию, ослабления обработки NULL и табличный режим — описано в абстракции пользовательской формулы. Эта статья описывает только то, как эти варианты записываются.
Параметры
-
NULLКлючевое слово, которое ослабляет правила обработки
NULLпо умолчанию у нетабличной формулы (в табличном режиме обе позиции игнорируются). Текст формулы выполняется как записан, над SQL-значениями аргументов, и платформа не проверяет, что он соблюдает правила своей формы: условие не-NULLсвойства — то условие, которое используется везде, где свойство служит условием, в операторе выбора или в присваивании, — определяется так, как описано ниже, а значение, читаемое как есть (при экспорте или на форме), — это результат SQL-текста. В двух формах без завершающего ключевого слова аргумент, равныйNULLпо построению, — литералNULLили локальное свойство без значения — делает свойствоNULLбез выполнения формулы. Поэтому формула должна сама соблюдать правила своей формы:- без ключевого слова — свойство не
NULL, когда все его аргументы неNULL. Формула обязана вернуть для них не-NULLзначение, а приNULLв любом аргументе —NULL: SQL-функции, возвращающей значение дляNULLна входе (concat,COALESCE,string_to_arrayсNULL-разделителем), нужна явная проверка (CASE WHEN $2 IS NULL THEN NULL ELSE ... END), иначе значение, читаемое как есть, расходится с условием. - перед
className— формула может возвращатьNULLи для не-NULLаргументов: свойство неNULL, когда вычисленное формулой значение неNULL, поэтому формула выполняется и надNULL-аргументами и обязана возвращать для нихNULL. - в конце — формула является объединением своих аргументов: она выполняется над
NULL-аргументами, включая литералNULL, а свойство неNULL, когда хотя бы один аргумент неNULL. Формула обязана вернуть в этом случае не-NULLзначение, а при всехNULL-аргументах —NULL. Её результат не проверяется. Если указаны оба ключевых слова, действует эта форма.
- без ключевого слова — свойство не
-
classNameИмя встроенного класса возвращаемого свойством значения. Если не задано, результирующим классом считается общий предок всех операндов свойства. Обязателен для табличных формул (см. список параметров ниже): колонке-значению возвращаемой таблицы нужен явный тип.
-
valueIdИдентификатор или строковый литерал сразу после
className. Задаёт имя колонки-значения в таблице, возвращаемой формулой — обязателен для табличных формул (см. список параметров ниже) и игнорируется для нетабличных. Форма со строковым литералом обычно используется для указания существующей колонки во внешней таблице, а форма с идентификатором — для значения, возвращаемого set-returning функцией. -
syntaxType1, ..., syntaxTypeNКлючевые слова, определяющие типы диалектов SQL. На данный момент поддерживаются следующие типы:
PG- синтаксис PostgreSQLMS- синтаксис MS SQL Server
Если тип диалекта не задан явно, то соответствующий текст формулы устанавливается, как текст по умолчанию. Каждый из типов (или отсутствие типа) должен встречаться в операторе не более одного раза.
-
text1, ..., textNСтроковые литералы, каждый из которых содержит формулу в SQL-синтаксисе. Параметры формулы подставляются как
$1,$2, ... по позиции либо как$paramId, если у параметра есть имя. Нумерация позиционных параметров начинается с1. Если задано несколько реализаций (по одной на диалект плюс опционально умолчательная), все они должны описывать один и тот же набор параметров — несовпадение арности между ними отклоняется на этапе разбора. -
classId1 ... classIdKКлассы параметров формулы. Если список параметров опущен, классы параметров берутся из внешнего объявления свойства. Арность результирующего свойства равна большему из
Kи максимального позиционного индекса, на который ссылается текст формулы. Позиционные обращения за пределыKрасширяют список автогенерируемыми параметрами. -
paramId1 ... paramIdKИмена, по которым текст формулы ссылается на параметры как
$paramIdвместо позиции. Каждое — идентификатор или строковый литерал. Параметр может быть без имени.Используемые в тексте формулы параметры передаются как входы в SQL-выражение в момент вычисления. Неиспользуемые становятся ключевыми колонками возвращаемой таблицы (см.
valueIdвыше для колонки-значения) и должны совпадать по именам с колонками, которые возвращает SQL-выражение. Единственный неиспользуемый параметр классаINTEGERс именемrow— отдельный случай: платформа подставляет для него номера строк черезROW_NUMBER() OVER (), поэтому такая идиома работает с любым табличным SQL-выражением.
Примеры
// свойство с двумя параметрами: округляемым числом и количеством знаков после запятой
round(number, digits) = FORMULA 'round(CAST(($1) as numeric),$2)';
// свойство, преобразовывающее значение, переданное в качестве аргумента, к строковому типу длиной в 15 символов.
toString15(str) = FORMULA BPSTRING[15] 'CAST($1 AS character(15))';
// свойство с двумя различными реализациями для разных диалектов SQL
jumpWorkdays = FORMULA NULL DATE PG 'jumpWorkdays($1, $2, $3)', MS 'dbo.jumpWorkdays($1, $2, $3)';
// обращение к параметрам по имени: $json / $field берутся из внешней сигнатуры
field (JSON json, STRING field) = FORMULA JSON 'jsonb_extract_path($json, $field)';
// явный список параметров с именами для $date / $time
toDateTime = FORMULA DATETIME '$date + $time' (DATE date, TIME time);
// табличная формула: `row` не используется в тексте, поэтому становится ключевой колонкой
// таблицы, возвращаемой jsonb_array_elements; `value` задаёт имя колонки-значения
array (JSON json, INTEGER row) = FORMULA JSON value 'jsonb_array_elements($json)';
// табличная формула с именованной ключевой колонкой: jsonb_each возвращает строки (key, value);
// `key` (неиспользуемый параметр) и `value` (valueId) совпадают с именами колонок этой записи
map (JSON json, STRING key) = FORMULA JSON value 'jsonb_each($json)';
// подключение внешней таблицы: текст формулы — имя таблицы, строковый литерал после
// STRING задаёт имя колонки-значения, а `key0` — ключевая колонка этой внешней таблицы
country (LONG key0) = FORMULA STRING 'country_name' '_auto_country';
// завершающее NULL: формула выполняется над NULL-аргументами, свойство не NULL, когда не NULL хотя бы один аргумент
firstNonNull = FORMULA TEXT 'COALESCE($1, $2)' (TEXT name, TEXT login) NULL;