Ниже описаны функции общего назначения, а для специализированных функций есть отдельные статьи: агрегатные, оконные, а также для работы со списками, словарями, структурами, типами данных и генерацией кода.
Перебирает аргументы слева направо и возвращает первый найденный непустой аргумент. Чтобы результат получился гарантированно непустым (не optional типа), самый правый аргумент должен быть такого типа (зачастую используют литерал). При одном аргументе возвращает его без изменений.
COALESCE(T?, ..., T)->T
COALESCE(T?, ..., T?)->T?
Позволяет передавать потенциально пустые значения в функции, которые не умеют обрабатывать их самостоятельно.
Доступен краткий формат записи в виде оператора ??
. Можно использовать алиас NVL
.
SELECT COALESCE(
maybe_empty_column,
"it's empty!"
) FROM my_table;
SELECT
maybe_empty_column ?? "it's empty!"
FROM my_table;
SELECT NVL(
maybe_empty_column,
"it's empty!"
) FROM my_table;
Все три примера выше эквивалентны.
Возвращает длину строки в байтах. Также эта функция доступна под именем LEN
.
LENGTH(T)->Uint32
LENGTH(T?)->Uint32?
SELECT LENGTH("foo");
SELECT LEN("bar");
{% note info %}
Для вычисления длины строки в unicode символах можно воспользоваться функцией Unicode::GetLength.
Для получения числа элементов в списке нужно использовать функцию ListLength.
{% endnote %}
Возвращает подстроку.
Substring(String[, Uint32? [, Uint32?]])->String
Substring(String?[, Uint32? [, Uint32?]])->String?
Обязательные аргументы:
NULL
, означающий «от начала».Опциональные аргументы:
NULL
по умолчанию, означающий «до конца исходной строки»).Индексация с нуля. Если указанные позиция и длина выходят за пределы строки, возвращает пустую строку. Если входная строка является опциональной, то таким же является и результат.
SELECT SUBSTRING("abcdefg", 3, 1); -- d
SELECT SUBSTRING("abcdefg", 3); -- defg
SELECT SUBSTRING("abcdefg", NULL, 3); -- abc
Поиск позиции подстроки в строке.
Find(String, String[, Uint32?])->Uint32?
Find(String?, String[, Uint32?])->Uint32?
Find(Utf8, Utf8[, Uint32?])->Uint32?
Find(Utf8?, Utf8[, Uint32?])->Uint32?
Обязательные аргументы:
Опциональные аргументы:
NULL
по умолчанию, означающий «от начала исходной строки»).Возвращает первую найденную позицию подстроки или NULL
, означающий что искомая подстрока с указанной позиции не найдена.
SELECT FIND("abcdefg_abcdefg", "abc"); -- 0
SELECT FIND("abcdefg_abcdefg", "abc", 1); -- 8
SELECT FIND("abcdefg_abcdefg", "abc", 9); -- null
Обратный поиск позиции подстроки в строке, от конца к началу.
RFind(String, String[, Uint32?])->Uint32?
RFind(String?, String[, Uint32?])->Uint32?
RFind(Utf8, Utf8[, Uint32?])->Uint32?
RFind(Utf8?, Utf8[, Uint32?])->Uint32?
Обязательные аргументы:
Опциональные аргументы:
NULL
по умолчанию, означающий «от конца исходной строки»).Возвращает первую найденную позицию подстроки или NULL
, означающий, что искомая подстрока с указанной позиции не найдена.
SELECT RFIND("abcdefg_abcdefg", "bcd"); -- 9
SELECT RFIND("abcdefg_abcdefg", "bcd", 8); -- 1
SELECT RFIND("abcdefg_abcdefg", "bcd", 0); -- null
Проверка наличия префикса или суффикса в строке.
StartsWith(T str, U prefix)->Bool[?]
EndsWith(T str, U suffix)->Bool[?]
Обязательные аргументы:
Аргументы должны иметь тип String
/Utf8
(или опциональный String
/Utf8
) либо строковый PostgreSQL тип (PgText
/PgBytea
/PgVarchar
).
Результатом функции является опциональный Bool, за исключением случая, когда оба аргумента неопциональные – в этом случае возвращается Bool.
SELECT StartsWith("abc_efg", "abc") AND EndsWith("abc_efg", "efg"); -- true
SELECT StartsWith("abc_efg", "efg") OR EndsWith("abc_efg", "abc"); -- false
SELECT StartsWith("abcd", NULL); -- null
SELECT EndsWith(NULL, Utf8("")); -- null
SELECT StartsWith("abc_efg"u, "abc"p) AND EndsWith("abc_efg", "efg"pv); -- true
Проверяет условие IF(condition_expression, then_expression, else_expression)
.
Является упрощенной альтернативой для CASE WHEN ... THEN ... ELSE ... END.
IF(Bool, T, T)->T
IF(Bool, T)->T?
Аргумент else_expression
можно не указывать. В этом случае, если условие ложно (condition_expression
вернул false
), будет возвращено пустое значение с типом, соответствующим then_expression
и допускающим значение NULL
. Таким образом, у результата получится optional тип данных.
SELECT
IF(foo > 0, bar, baz) AS bar_or_baz,
IF(foo > 0, foo) AS only_positive_foo
FROM my_table;
Заменяет значения NaN
(not a number) в выражениях типа Float
, Double
или Optional.
NANVL(Float, Float)->Float
NANVL(Double, Double)->Double
Аргументы:
NaN
.Если один из агрументов Double
, то в выдаче Double
, иначе Float
. Если один из агрументов Optional
, то и в выдаче Optional
.
SELECT
NANVL(double_column, 0.0)
FROM my_table;
Генерирует псевдослучайное число:
Random()
— число с плавающей точкой (Double) от 0 до 1;RandomNumber()
— целое число из всего диапазона Uint64;RandomUuid()
— Uuid version 4.Random(T1[, T2, ...])->Double
RandomNumber(T1[, T2, ...])->Uint64
RandomUuid(T1[, T2, ...])->Uuid
При генерации случайных чисел аргументы не используются и нужны исключительно для управления моментом вызова. В каждый момент вызова возвращается новое случайное число. Поэтому:
Повторный вызов Random в рамках одного запроса при идентичном наборе аргументов возвращает тот же самый набор случайных чисел. Важно понимать, что речь именно про сами аргументы (текст между круглыми скобками), а не их значения.
Вызовы Random с одним и тем же набором аргументов в разных запросах вернут разные наборы случайных чисел.
{% note warning %}
Если Random используется в именованных выражениях, то его однократное вычисление не гарантируется. В зависимости от оптимизаторов и среды исполнения он может посчитаться как один раз, так и многократно. Для гарантированного однократного подсчета необходимо в этом случае материализовать именованное выражение в таблицу.
{% endnote %}
Сценарии использования:
SELECT RANDOM(1);
— получить одно случайное значение на весь запрос и несколько раз его использовать (чтобы получить несколько, можно передать разные константы любого типа);SELECT RANDOM(1) FROM table;
— одно и то же случайное число на каждую строку таблицы;SELECT RANDOM(1), RANDOM(2) FROM table;
— по два случайных числа на каждую строку таблицы, все числа в каждой из колонок одинаковые;SELECT RANDOM(some_column) FROM table;
— разные случайные числа на каждую строку таблицы;SELECT RANDOM(some_column), RANDOM(some_column) FROM table;
— разные случайные числа на каждую строку таблицы, но в рамках одной строки — два одинаковых числа;SELECT RANDOM(some_column), RANDOM(some_column + 1) FROM table;
или SELECT RANDOM(some_column), RANDOM(other_column) FROM table;
— две колонки, и все с разными числами.SELECT
Random(key) -- [0, 1)
FROM my_table;
SELECT
RandomNumber(key) -- [0, Max<Uint64>)
FROM my_table;
SELECT
RandomUuid(key) -- Uuid version 4
FROM my_table;
SELECT
RANDOM(column) AS rand1,
RANDOM(column) AS rand2, -- same as rand1
RANDOM(column, 1) AS randAnd1, -- different from rand1/2
RANDOM(column, 2) AS randAnd2 -- different from randAnd1
FROM my_table;
Строит Callable
по заданному названию функции и опциональным external user types
, RunConfig
и TypeConfig
.
Udf(Foo::Bar)
— Функция Foo::Bar
без дополнительных параметров.Udf(Foo::Bar)(1, 2, 'abc')
— Вызов udf Foo::Bar
.Udf(Foo::Bar, Int32, @@{"device":"AHCI"}@@ as TypeConfig")(1, 2, 'abc')
— Вызов udf Foo::Bar
с дополнительным типом Int32
и указанным TypeConfig
.Udf(Foo::Bar, "1e9+7" as RunConfig")(1, 'extended' As Precision)
— Вызов udf Foo::Bar
с указанным RunConfig
и именоваными параметрами.Udf(Callable[, T1, T2, ..., T_N][, V1 as TypeConfig][,V2 as RunConfig]])->Callable
Где T1
, T2
, и т. д. -- дополнительные (external
) пользовательские типы.
$IsoParser = Udf(DateTime2::ParseIso8601);
SELECT $IsoParser("2022-01-01");
SELECT Udf(Unicode::IsUtf)("2022-01-01")
$config = @@{
"name":"MessageFoo",
"meta": "..."
}@@;
SELECT Udf(Protobuf::TryParse, $config As TypeConfig)("")
CurrentUtcDate()
, CurrentUtcDatetime()
и CurrentUtcTimestamp()
- получение текущей даты и/или времени в UTC. Тип данных результата указан в конце названия функции.
CurrentUtcDate(...)->Date
CurrentUtcDatetime(...)->Datetime
CurrentUtcTimestamp(...)->Timestamp
Аргументы опциональны и работают по тому же принципу, что и у RANDOM.
SELECT CurrentUtcDate();
SELECT CurrentUtcTimestamp(TableRow()) FROM my_table;
CurrentTzDate()
, CurrentTzDatetime()
и CurrentTzTimestamp()
- получение текущей даты и/или времени в указанной в первом аргументе IANA временной зоне. Тип данных результата указан в конце названия функции.
CurrentTzDate(String, ...)->TzDate
CurrentTzDatetime(String, ...)->TzDatetime
CurrentTzTimestamp(String, ...)->TzTimestamp
Последующие аргументы опциональны и работают по тому же принципу, что и у RANDOM.
SELECT CurrentTzDate("Europe/Moscow");
SELECT CurrentTzTimestamp("Europe/Moscow", TableRow()) FROM my_table;
Добавление информации о временной зоне к дате/времени, заданных в UTC. При выводе в результате SELECT
или после CAST
в String
будут применены правила временной зоны по вычислению смещения времени.
AddTimezone(Date, String)->TzDate
AddTimezone(Date?, String)->TzDate?
AddTimezone(Datetime, String)->TzDatetime
AddTimezone(Datetime?, String)->TzDatetime?
AddTimezone(Timestamp, String)->TzTimestamp
AddTimezone(Timestamp?, String)->TzTimestamp?
Аргументы:
Date
/Datetime
/Timestamp
;Тип результата - TzDate
/TzDatetime
/TzTimestamp
, в зависимости от типа данных входа.
SELECT AddTimezone(Datetime("2018-02-01T12:00:00Z"), "Europe/Moscow");
Удаление информации о временной зоне и перевод в дату/время, заданные в UTC.
RemoveTimezone(TzDate)->Date
RemoveTimezone(TzDate?)->Date?
RemoveTimezone(TzDatetime)->Datetime
RemoveTimezone(TzDatetime?)->Datetime?
RemoveTimezone(TzTimestamp)->Timestamp
RemoveTimezone(TzTimestamp?)->Timestamp?
Аргументы:
TzDate
/TzDatetime
/TzTimestamp
.Тип результата - Date
/Datetime
/Timestamp
, в зависимости от типа данных входа.
SELECT RemoveTimezone(TzDatetime("2018-02-01T12:00:00,Europe/Moscow"));
Version()
возвращает строку, описывающую текущую версию узла, обрабатывающего запрос. В некоторых случаях, например, во время постепенного обновлений кластера, она может возвращать разные строки в зависимости от того, какой узел обрабатывает запрос. Функция не принимает никаких аргументов.
SELECT Version();
Возвращает минимальный или максимальный среди N аргументов. Эти функции позволяют не использовать стандартную для SQL конструкцию CASE WHEN a < b THEN a ELSE b END
, которая была бы особенно громоздкой для N больше двух.
MIN_OF(T[,T,...})->T
MAX_OF(T[,T,...})->T
Типы аргументов должны быть приводимы друг к другу и могут допускать значение NULL
.
GREATEST
является синонимом к MAX_OF
, а LEAST
— к MIN_OF
.
SELECT MIN_OF(1, 2, 3);
Создает контейнеры соответствующих типов. Также доступна операторная запись литералов контейнеров.
Особенности:
AsTuple
и AsStruct
могут быть вызваны без аргументов, а также аргументы могут иметь разные типы.AsStruct
задаются через AsStruct(field_value AS field_name)
.AsList()
без аргументов, в этом случае это выражение будет иметь тип EmptyList
.AsDict()
без аргументов, в этом случае это выражение будет иметь тип EmptyDict
.AsSet()
без аргументов, в этом случае это выражение будет иметь тип EmptyDict
.AsList
выводит общий тип элементов списка. При несовместимых типах генерируется ошибка типизации.AsDict
выводит раздельно общие типы ключей и значений. При несовместимых типах генерируется ошибка типизации.AsSet
выводит общие типы ключей. При несовместимых типах генерируется ошибка типизации.AsListStrict
, AsDictStrict
, AsSetStrict
требуют одинакового типа для аргументов.AsDict
и AsDictStrict
в качестве аргументов ожидаются Tuple
из двух элементов: ключ и значение, соответственно. Если ключи повторяются, в словаре останется только значение для первого ключа.AsSet
и AsSetStrict
в качестве аргументов ожидаются ключи.SELECT
AsTuple(1, 2, "3") AS `tuple`,
AsStruct(
1 AS a,
2 AS b,
"3" AS c
) AS `struct`,
AsList(1, 2, 3) AS `list`,
AsDict(
AsTuple("a", 1),
AsTuple("b", 2),
AsTuple("c", 3)
) AS `dict`,
AsSet(1, 2, 3) AS `set`
Для некоторых контейнеров возможна операторная форма записи их литеральных значений:
(value1, value2...)
;<|name1: value1, name2: value2...|>
;[value1, value2,...]
;{key1: value1, key2: value2...}
;{key1, key2...}
.Во всех случаях допускается незначащая хвостовая запятая. Для кортежа с одним элементом эта запятая является обязательной - (value1,)
.
Для имен полей в литерале структуры допускается использовать выражение, которое можно посчитать в evaluation time, например, строковые литералы, а также идентификаторы (в том числе в backticks).
Для списка внутри используется функция AsList, словаря - AsDict, множества - AsSet, кортежа - AsTuple, структуры - AsStruct.
$name = "computed " || "member name";
SELECT
(1, 2, "3") AS `tuple`,
<|
`complex member name`: 2.3,
b: 2,
$name: "3",
"inline " || "computed member name": false
|> AS `struct`,
[1, 2, 3] AS `list`,
{
"a": 1,
"b": 2,
"c": 3,
} AS `dict`,
{1, 2, 3} AS `set`
Variant()
создает значение варианта над кортежем или структурой.
Variant(T, String, Type<Variant<...>>)->Variant<...>
Аргументы:
$var_type = Variant<foo: Int32, bar: Bool>;
SELECT
Variant(6, "foo", $var_type) as Variant1Value,
Variant(false, "bar", $var_type) as Variant2Value;
AsVariant()
создает значение варианта над структурой с одним полем. Это значение может быть неявно преобразовано к любому варианту над структурой, в которой совпадает для этого имени поля тип данных и могут быть дополнительные поля с другими именами.
AsVariant(T, String)->Variant
Аргументы:
SELECT
AsVariant(6, "foo") as VariantValue
Обрабатывает возможные значения варианта, представленного структурой или кортежем, с использованием предоставленных функций-обработчиков для каждого из его полей/элементов.
Visit(Variant<key1: K1, key2: K2, ...>, K1->R AS key1, K2->R AS key2, ...)->R
Visit(Variant<K1, K2, ...>, K1->R, K2->R, ...)->R
VisitOrDefault(Variant<K1, K2, ...>{Flags:AutoMap}, R, [K1->R, [K2->R, ...]])->R
VisitOrDefault(Variant<key1: K1, key2: K2, ...>{Flags:AutoMap}, R, [K1->R AS key1, [K2->R AS key2, ...]])->R
VisitOrDefault
принимает дополнительный позиционный аргумент (на втором месте), представляющий значение по умолчанию, и позволяет не указывать некоторые обработчики.$vartype = Variant<num: Int32, flag: Bool, str: String>;
$handle_num = ($x) -> { return 2 * $x; };
$handle_flag = ($x) -> { return If($x, 200, 10); };
$handle_str = ($x) -> { return Unwrap(CAST(LENGTH($x) AS Int32)); };
$visitor = ($var) -> { return Visit($var, $handle_num AS num, $handle_flag AS flag, $handle_str AS str); };
SELECT
$visitor(Variant(5, "num", $vartype)), -- 10
$visitor(Just(Variant(True, "flag", $vartype))), -- Just(200)
$visitor(Just(Variant("somestr", "str", $vartype))), -- Just(7)
$visitor(Nothing(OptionalType($vartype))), -- Nothing(Optional<Int32>)
$visitor(NULL) -- NULL
;
Возвращает значение гомогенного варианта (т.е. содержащего поля/элементы одного типа).
VariantItem(Variant<key1: K, key2: K, ...>{Flags:AutoMap})->K
VariantItem(Variant<K, K, ...>{Flags:AutoMap})->K
$vartype1 = Variant<num1: Int32, num2: Int32, num3: Int32>;
SELECT
VariantItem(Variant(7, "num2", $vartype1)), -- 7
VariantItem(Just(Variant(5, "num1", $vartype1))), -- Just(5)
VariantItem(Nothing(OptionalType($vartype1))), -- Nothing(Optional<Int32>)
VariantItem(NULL) -- NULL
;
Возвращает активное поле (активный индекс) варианта поверх структуры (кортежа).
Way(Variant<key1: K1, key2: K2, ...>{Flags:AutoMap})->Utf8
Way(Variant<K1, K2, ...>{Flags:AutoMap})->Uint32
$vr = Variant(1, "0", Variant<Int32, String>);
$vrs = Variant(1, "a", Variant<a:Int32, b:String>);
SELECT Way($vr); -- 0
SELECT Way($vrs); -- "a"
Создает экзмепляр гомогенного варианта (т.е. содержащего поля/элементы одного типа), причем индекс или поле варианта можно задавать динамически. При несуществующем индексе или имени поля будет возвращен NULL
.
Обратная функция - VariantItem.
DynamicVariant(item:T,index:Uint32?,Variant<T, T, ...>)->Optional<Variant<T, T, ...>>
DynamicVariant(item:T,index:Utf8?,Variant<key1: T, key2: T, ...>)->Optional<Variant<key1: T, key2: T, ...>>
$dt = Int32;
$tvt = Variant<$dt,$dt>;
SELECT ListMap([(10,0u),(20,2u),(30,NULL)],($x)->(DynamicVariant($x.0,$x.1,$tvt))); -- [0: 10,NULL,NULL]
$dt = Int32;
$svt = Variant<x:$dt,y:$dt>;
SELECT ListMap([(10,'x'u),(20,'z'u),(30,NULL)],($x)->(DynamicVariant($x.0,$x.1,$svt))); -- [x: 10,NULL,NULL]
Enum()
создает значение перечисления.
Enum(String, Type<Enum<...>>)->Enum<...>
Аргументы:
$enum_type = Enum<Foo, Bar>;
SELECT
Enum("Foo", $enum_type) as Enum1Value,
Enum("Bar", $enum_type) as Enum2Value;
AsEnum()
создает значение перечисления с одним элементом. Это значение может быть неявно преобразовано к любому перечислению, содержащему такое имя.
AsEnum(String)->Enum<'tag'>
Аргументы:
SELECT
AsEnum("Foo");
Оборачивает значение в Tagged тип данных с указанной меткой с сохранением физического типа данных. Untag
— обратная операция.
AsTagged(T, tagName:String)->Tagged<T,tagName>
AsTagged(T?, tagName:String)->Tagged<T,tagName>?
Untag(Tagged<T, tagName>)->T
Untag(Tagged<T, tagName>?)->T?
Обязательные аргументы:
Возвращает копию значения из первого аргумента с указанной меткой в типе данных.
Примеры сценариев использования:
Доступ к текущему имени таблицы, что бывает востребовано при использовании CONCAT и других подобных механизмов.
TablePath()->String
Аргументов нет. Возвращает строку с полным путём, либо пустую строку и warning при использовании в неподдерживаемом контексте (например, при работе с подзапросом или диапазоном из 1000+ таблиц).
{% note info %}
Функции TablePath, TableName и TableRecordIndex не работают для временных и анонимных таблиц (возвращают пустую строку или 0 для TableRecordIndex).
Данные функции вычисляются в момент выполнения проекции в SELECT
, и к этому моменту текущая таблица уже может быть временной.
Чтобы избежать такой ситуации, следует поместить вычисление этих функций в подзапрос, как это сделано во втором примере ниже.
{% endnote %}
SELECT TablePath() FROM CONCAT(table_a, table_b);
SELECT key, tpath_ AS path FROM (SELECT a.*, TablePath() AS tpath_ FROM RANGE(`my_folder`) AS a)
WHERE key IN $subquery;
Получить имя таблицы из пути к таблице. Путь можно получить через функцию TablePath.
TableName()->String
TableName(String)->String
TableName(String, String)->String
Необязательные аргументы:
TablePath()
(также см. его ограничения);USE hahn;
SELECT TableName() FROM CONCAT(table_a, table_b);
Доступ к текущему порядковому номеру строки в исходной физической таблице, начиная с 1 (зависит от реализации хранения).
TableRecordIndex()->Uint64
Аргументов нет. При использовании в сочетании с CONCAT и другими подобными механизмами нумерация начинается заново для каждой таблицы на входе. В случае использования в некорректном контексте возвращает 0.
SELECT TableRecordIndex() FROM my_table;
Получение всей строки таблицы целиком в виде структуры. Аргументов нет. JoinTableRow
в случае JOIN
-ов всегда возвращает структуру с префиксами таблиц.
TableRow()->Struct
SELECT TableRow() FROM my_table;
FilePath(String)->String
FileContent(String)->String
Аргумент FileContent
и FilePath
— строка с алиасом.
SELECT "Content of "
|| FilePath("my_file.txt")
|| ":\n"
|| FileContent("my_file.txt");
Получение пути до корня директории с несколькими «приложенными» файлами с указанным общим префиксом.
FolderPath(String)->String
Аргумент — строка с префиксом среди алиасов.
Также см. PRAGMA File и PRAGMA Folder.
PRAGMA File("foo/1.txt", "http://url/to/somewhere");
PRAGMA File("foo/2.txt", "http://url/to/somewhere/else");
PRAGMA File("bar/3.txt", "http://url/to/some/other/place");
SELECT FolderPath("foo"); -- в директории по возвращённому пути будут
-- находиться файлы 1.txt и 2.txt, скачанные по указанным выше ссылкам
Получить из приложенного текстового файла список значений. Может использоваться в сочетании с IN и прикладыванием файла по URL.
Поддерживается только один формат файла — по одному значению на строку.
ParseFile(String, String)->List<T>
Два обязательных аргумента:
{% note info %}
Возвращаемое значение - ленивый список. Для многократного использования его нужно обернуть в функцию ListCollect
{% endnote %}
SELECT ListLength(ParseFile("String", "my_file.txt"));
SELECT * FROM my_table
WHERE int_column IN ParseFile("Int64", "my_file.txt");
Проверка пользовательских условий:
Ensure()
— проверка верности предиката во время выполнения запроса.EnsureType()
— проверка точного соответствия типа выражения указанному.EnsureConvertibleTo()
— мягкая проверка соответствия типа выражения, работающая по тем же правилам, что и неявное приведение типов.Если проверка не прошла успешно, то весь запрос завершается с ошибкой.
Ensure(T, Bool, String)->T
EnsureType(T, Type<T>, String)->T
EnsureConvertibleTo(T, Type<T>, String)->T
Аргументы:
true
. В остальных функциях — тип данных, который может быть получен через предназначенные для этого функции, либо строковый литерал с текстовым описанием типа.Для проверки условий по финальному результату вычисления Ensure удобно использовать в сочетании с DISCARD SELECT.
SELECT Ensure(
value,
value < 100,
"value out or range"
) AS value FROM my_table;
SELECT EnsureType(
value,
TypeOf(other_value),
"expected value and other_value to be of same type"
) AS value FROM my_table;
SELECT EnsureConvertibleTo(
value,
Double?,
"expected value to be numeric"
) AS value FROM my_table;
AssumeStrict(T)->T
Функция AssumeStrict
возвращает свой аргумент. Использование этой функции – способ сказать оптимизатору YQL, что выражение в аргументе является строгим, т.е. свободным от ошибок времени выполнения.
Большинство встроенных функций и операторов YQL являются строгими, но есть исключения – например Unwrap и Ensure.
Кроме того, нестрогим выражением считается вызов UDF.
Если есть уверенность, что при вычислении выражения ошибок времени выполнения на самом деле не возникает, то имеет смысл использовать AssumeStrict
.
SELECT * FROM T1 AS a JOIN T2 AS b USING(key)
WHERE AssumeStrict(Unwrap(CAST(a.key AS Int32))) == 1;
В данном примере мы считаем что все значения текстовой колонки a.key
в таблице T1
являются валидными числами, поэтому Unwrap не приводит к ошибке.
При налиичии AssumeStrict
оптимизатор сможет выполнить сначала фильтрацию, а потом JOIN.
Без AssumeStrict
такая оптимизация не выполняется – оптимизатор обязан учитывать ситуацию, при которой в колонке a.key
есть нечисловые значения, которые отфильтровываются JOIN
ом.
Likely(Bool)->Bool
Likely(Bool?)->Bool?
Функция Likely
возвращает свой аргумент. Функция является подсказкой оптимизатору и говорит о том, что в большинстве случаев ее аргумент будет иметь значение True
.
Например, наличие такой функции в WHERE
означает что фильтр является слабоселективным.
SELECT * FROM T1 AS a JOIN T2 AS b USING(key)
WHERE Likely(a.amount > 0) -- почти всегда верно
При наличии Likely
оптимизатор не будет стараться выполнить фильтрацию перед JOIN
.
Возможность выполнить выражение до начала основного расчета и подставить его результат в запрос как литерал (константу). Во многих контекстах, где в стандартном SQL ожидалась бы только константа (например, в именах таблиц, количестве строк в LIMIT и т.п.) этот функционал активируется неявным образом автоматически.
EvaluateExpr может использоваться в тех местах, где грамматикой уже ожидается выражение. Например, с его помощью можно:
EvaluateAtom позволяет динамически создать атом, но т.к. ими в основном оперирует более низкий уровень s-expressions, то использовать эту функцию напрямую как правило не рекомендуется.
Единственный аргумент у обоих функций — само выражение для вычисления и подстановки.
Ограничения:
$now = CurrentUtcDate();
SELECT EvaluateExpr(
DateTime::MakeDate(DateTime::StartOfWeek($now)
)
);
Для простых типов могут быть созданы литералы на основании строковых литералов.
<Простой тип>( <строка>[, <дополнительные атрибуты>] )
В отличие от CAST("myString" AS MyType)
:
Для типов данных Date
, Datetime
, Timestamp
и Interval
поддерживаются литералы только в формате, соответствующем ISO 8601. У Interval
есть следующие отличия от стандарта:
Для типов данных TzDate
, TzDatetime
, TzTimestamp
литералы также задаются в формате, соответствующем ISO 8601, но вместо опционального суффикса Z через запятую указывается IANA имя временной зоны, например, GMT или Europe/Moscow.
{% include decimal args %}
SELECT
Bool("true"),
Uint8("0"),
Int32("-1"),
Uint32("2"),
Int64("-3"),
Uint64("4"),
Float("-5"),
Double("6"),
Decimal("1.23", 5, 2), -- до 5 десятичных знаков, из которых 2 после запятой
String("foo"),
Utf8("привет"),
Yson("<a=1>[3;%false]"),
Json(@@{"a":1,"b":null}@@),
Date("2017-11-27"),
Datetime("2017-11-27T13:24:00Z"),
Timestamp("2017-11-27T13:24:00.123456Z"),
Interval("P1DT2H3M4.567890S"),
TzDate("2017-11-27,Europe/Moscow"),
TzDatetime("2017-11-27T13:24:00,America/Los_Angeles"),
TzTimestamp("2017-11-27T13:24:00.123456,GMT"),
Uuid("f9d5cc3f-f1dc-4d9c-b97e-766e57ca4ccb");
Конвертация простых типов данных в строку со своим бинарным представлением и обратно. Числа представляются в little endian.
ToBytes(T)->String
ToBytes(T?)->String?
FromBytes(String, Type<T>)->T?
FromBytes(String?, Type<T>)->T?
SELECT
ToBytes(123), -- "\u0001\u0000\u0000\u0000"
FromBytes(
"\xd2\x02\x96\x49\x00\x00\x00\x00",
Uint64
); -- 1234567890ul
Получение значение байта в строке по индексу от её начала. В случае некорректного индекса возвращается NULL
.
ByteAt(String, Uint32)->Uint8
ByteAt(String?, Uint32)->Uint8?
ByteAt(Utf8, Uint32)->Uint8
ByteAt(Utf8?, Uint32)->Uint8?
Аргументы:
String
или Utf8
;Uint32
.SELECT
ByteAt("foo", 0), -- 102
ByteAt("foo", 1), -- 111
ByteAt("foo", 9); -- NULL
TestBit()
, ClearBit()
, SetBit()
и FlipBit()
- проверить, сбросить, установить или инвертировать бит в беззнаковом числе по указанному порядковому номеру бита.
TestBit(T, Uint8)->Bool
TestBit(T?, Uint8)->Bool?
ClearBit(T, Uint8)->T
ClearBit(T?, Uint8)->T?
SetBit(T, Uint8)->T
SetBit(T?, Uint8)->T?
FlipBit(T, Uint8)->T
FlipBit(T?, Uint8)->T?
Аргументы:
TestBit возвращает true/false
. Остальные функции возвращают копию своего первого аргумента с проведенным соответствующим преобразованием.
SELECT
TestBit(1u, 0), -- true
SetBit(8u, 0); -- 9
Абсолютное значение числа.
Abs(T)->T
Abs(T?)->T?
SELECT Abs(-123); -- 123
Just()
- Изменить тип данных значения на optional от текущего типа данных (то есть T
превращается в T?
).
Just(T)->T?
SELECT
Just("my_string"); -- String?
Unwrap()
- Преобразование значения optional типа данных в соответствующий не-optional тип с ошибкой времени выполнений, если в данных оказался NULL
. Таким образом, T?
превращается в T
.
Если значение не является optional, то функция возвращает свой первый аргумент без изменений.
Unwrap(T?)->T
Unwrap(T?, Utf8)->T
Unwrap(T?, String)->T
Аргументы:
Обратная операция — Just.
$value = Just("value");
SELECT Unwrap($value, "Unexpected NULL for $value");
Nothing()
- Создать пустое значение указанного Optional типа данных.
Nothing(Type<T?>)->T?
SELECT
Nothing(String?); -- пустое значение (NULL) с типом String?
Подробнее о ParseType и других функциях для работы с типами данных.
Создать вызываемое значение с заданной сигнатурой из лямбда-функции. Обычно используется для того, чтобы размещать вызываемые значения в контейнерах.
Callable(Type<Callable<(...)->T>>, lambda)->Callable<(...)->T>
Аргументы:
$lambda = ($x) -> {
RETURN CAST($x as String)
};
$callables = AsTuple(
Callable(Callable<(Int32)->String>, $lambda),
Callable(Callable<(Bool)->String>, $lambda),
);
SELECT $callables.0(10), $callables.1(true);
Pickle()
и StablePickle()
сериализуют произвольный объект в последовательность байт, если это возможно. Типовыми несериализуемыми объектами являются Callable и Resource. Формат сериализации не версионируется, допускается использовать в пределах одного запроса. Для типа Dict функция StablePickle предварительно сортирует ключи, а для Pickle порядок элементов словаря в сериализованном представлении не определен.
Unpickle()
— обратная операция (десериализация), где первым аргументом передается тип данных результата, а вторым — строка с результатом Pickle()
или StablePickle()
.
Pickle(T)->String
StablePickle(T)->String
Unpickle(Type<T>, String)->T
SELECT *
FROM my_table
WHERE Digest::MurMurHash32(
Pickle(TableRow())
) % 10 == 0; -- в реальности лучше использовать TABLESAMPLE
$buf = Pickle(123);
SELECT Unpickle(Int32, $buf);
Преобразует структуру или кортеж, применяя лямбду к каждому элементу.
StaticMap(Struct<...>, lambda)->Struct<...>
StaticMap(Tuple<...>, lambda)->Tuple<...>
Аргументы:
Результат: структура или кортеж с аналогичным первому аргументу количеством и именованием элементов, а типы данных элементов определяются результатами лямбды.
SELECT *
FROM (
SELECT
StaticMap(TableRow(), ($item) -> {
return CAST($item AS String);
})
FROM my_table
) FLATTEN COLUMNS; -- преобразование всех колонок в строки
Поэлементно "склеивает" структуры или кортежи. Все аргументы (один и более) должны быть либо структурами с одинаковым набором полей, либо кортежами одинаковой длины. Результататом будет соответственно структура или кортеж. Каждый элемент результата – кортеж с соответствующими элементами из аргументов.
StaticZip(Struct, Struct)->Struct
StaticZip(Tuple, Tuple)->Tuple
$one = <|k1:1, k2:2.0|>;
$two = <|k1:3.0, k2:4|>;
-- поэлементное сложение двух структур
SELECT StaticMap(StaticZip($one, $two), ($tuple)->($tuple.0 + $tuple.1)) AS sum;
StaticFold(obj:Struct/Tuple, initVal, updateLambda)
StaticFold1(obj:Struct/Tuple, initLambda, updateLambda)
Статическая левоассоциативная свертка структуры или кортежа. Для кортежей свертка производится в порядке от меньшего индекса к большему, для структур порядок не гарантируется.
obj
- объект, элементы которого нужно свернутьinitVal
- (для StaticFold) исходное состояние сверткиinitLambda
- (для StaticFold1) функция для получения исходного состояния по первому элементуupdateLambda
- функция обновления состояния (принимает в аргументах следующий элемент объекта и предыдущее состояние)StaticFold(<|key_1:$el_1, key_2:$el_2, ..., key_n:$el_n|>, $init, $f)
преобразуется в свертку:
$f($el_n, ...$f($el_2, $f($init, el_1))...)
StaticFold1(<|key_1:$el_1, key_2:$el_2, ..., key_n:$el_n|>, $f0, $f)
:
$f($el_n, ...$f($el_2, $f($f0($init), el_1))...)
StaticFold1(<||>, $f0, $f)
вернет NULL
.
Аналогично работает и с кортежами.
Создать фабрику для агрегационных функций для того чтобы разделить процесс описания того, как агрегировать данные, и то, к каким данным это применять.
Аргументы:
Полученную фабрику можно использовать как второй параметр функции AGGREGATE_BY.
Если агрегационная функция работает на двух колонках вместо одной, как например, MIN_BY, то в AGGREGATE_BY первым аргументом передается Tuple
из двух значений. Подробнее это указано при описании такой агрегационной функции.
$factory = AggregationFactory("MIN");
SELECT
AGGREGATE_BY(value, $factory) AS min_value -- применить MIN агрегацию к колонке value
FROM my_table;
AggregateTransformInput()
преобразует фабрику для агрегационных функций, например, полученную через функцию AggregationFactory в другую фабрику, в которой перед началом выполнения агрегации производится указанное преобразование входных элементов.
Аргументы:
$f = AggregationFactory("sum");
$g = AggregateTransformInput($f, ($x) -> (cast($x as Int32)));
$h = AggregateTransformInput($f, ($x) -> ($x * 2));
SELECT ListAggregate([1,2,3], $f); -- 6
SELECT ListAggregate(["1","2","3"], $g); -- 6
SELECT ListAggregate([1,2,3], $h); -- 12
AggregateTransformOutput()
преобразует фабрику для агрегационных функций, например, полученную через функцию AggregationFactory в другую фабрику, в которой после окончания выполнения агрегации производится указанное преобразование результата.
Аргументы:
$f = AggregationFactory("sum");
$g = AggregateTransformOutput($f, ($x) -> ($x * 2));
SELECT ListAggregate([1,2,3], $f); -- 6
SELECT ListAggregate([1,2,3], $g); -- 12
Адаптирует фабрику для агрегационных функций, например, полученную через функцию AggregationFactory так, чтобы выполнять агрегацию над входными элементами - списками. Эта операция похожа на FLATTEN LIST BY - производится агрегация каждого элемента списка.
Аргументы:
$i = AggregationFactory("AGGREGATE_LIST_DISTINCT");
$j = AggregateFlatten($i);
SELECT AggregateBy(x, $j) from (
SELECT [1,2] as x
union all
SELECT [2,3] as x
); -- [1, 2, 3]
Полный список внутренних функций YQL находится в документации к s-expressions, альтернативному низкоуровневому синтаксису YQL. Любую из перечисленных там функций можно вызвать и из SQL синтаксиса, добавив к её имени префикс YQL::
, но это не рекомендуется делать, т.к. данный механизм предназначен в первую очередь для временного обхода возможных проблем, а также для нужд внутреннего тестирования.
Если функция доступна в SQL синтаксисе без префикса YQL::
, то её поведение имеет право отличаться от одноименной функции из документации по s-expressions, если таковая существует.