Обычные функции
Существует по меньшей мере* два типа функций — обычные функции (их просто называют «функциями») и агрегатные функции. Это совершенно разные понятия. Обычные функции работают так, как если бы они применялись к каждой строке отдельно (для каждой строки результат функции не зависит от остальных строк). Агрегатные функции накапливают набор значений из различных строк (то есть зависят от всего набора строк).
В этом разделе рассматриваются обычные функции. Об агрегатных функциях см. раздел «Агрегатные функции».
Существует третий тип функций, к которому относится функция 'arrayJoin'. Отдельно также можно упомянуть табличные функции.
Строгая типизация
В отличие от стандартного SQL, ClickHouse использует строгую типизацию. Другими словами, он не выполняет неявные преобразования типов. Каждая функция работает с определённым набором типов. Это означает, что иногда необходимо использовать функции приведения типов.
Устранение общих подвыражений
Все выражения в запросе, которые имеют одинаковое AST (одинаковое представление или один и тот же результат синтаксического разбора), считаются эквивалентными по значению. Такие выражения объединяются и выполняются один раз. Идентичные подзапросы также устраняются таким образом.
Типы результатов
Все функции возвращают одно значение как результат (не несколько значений и не отсутствие значения). Тип возвращаемого значения обычно определяется только типами аргументов, а не их значениями. Исключениями являются функция tupleElement (оператор a.N) и функция toFixedString.
Константы
Для упрощения реализации некоторые функции могут работать только с константами для части своих аргументов. Например, правый аргумент оператора LIKE должен быть константой.
Почти все функции возвращают константу для константных аргументов. Исключение — функции, генерирующие случайные числа.
Функция now возвращает разные значения для запросов, выполненных в разное время, но результат считается константой, поскольку константность важна только в пределах одного запроса.
Константное выражение также считается константой (например, правая часть оператора LIKE может быть составлена из нескольких констант).
Функции могут быть реализованы по-разному для константных и неконстантных аргументов (выполняется разный код). При этом результаты для константы и для обычного столбца, содержащего одно и то же значение во всех строках, должны совпадать.
Обработка NULL
Функции ведут себя следующим образом:
- Если хотя бы один из аргументов функции имеет значение
NULL, результат функции также будетNULL. - Особое поведение, описанное отдельно в описании каждой функции. В исходном коде ClickHouse эти функции имеют
UseDefaultImplementationForNulls=false.
Константность
Функции не могут изменять значения своих аргументов — любые изменения отражаются только в возвращаемом результате. Поэтому результат вычисления отдельных функций не зависит от порядка, в котором функции указаны в запросе.
Функции высшего порядка
Оператор -> и функции lambda(params, expr)
Функции высшего порядка могут принимать в качестве функционального аргумента только лямбда-функции. Чтобы передать лямбда-функцию в функцию высшего порядка, используйте оператор ->. Левая часть стрелки содержит формальный параметр, который может быть любым идентификатором, или несколько формальных параметров — любые идентификаторы в кортеже. Правая часть стрелки содержит выражение, которое может использовать эти формальные параметры, а также любые столбцы таблицы.
Примеры:
Лямбда-функцию, принимающую несколько аргументов, также можно передать функции высшего порядка. В этом случае функции высшего порядка передаётся несколько массивов одинаковой длины, с которыми будут сопоставляться эти аргументы.
Для некоторых функций первый аргумент (лямбда-функцию) можно опустить. В этом случае подразумевается тождественное отображение.
Имена простых функций как лямбда-выражения
Вместо того чтобы записывать полное лямбда-выражение, можно передать имя функции напрямую в функцию высшего порядка. Имя функции автоматически преобразуется в эквивалентное лямбда-выражение.
Например, следующие пары эквивалентны:
Это работает со встроенными функциями, SQL UDF, исполняемыми UDF и WebAssembly UDF. При неоднозначности имена столбцов и псевдонимов имеют приоритет над именами функций.
Арность лямбда-функции определяется по внутренней функции. Например, arrayMap(plus, ...) использует арность 2, потому что plus принимает два аргумента, поэтому это также работает с входными данными в виде кортежей, например arrayMap(plus, [(1, 10), (2, 20)]), где элементы кортежа распаковываются в аргументы лямбда-функции.
Для вариативных внутренних функций (например, concat, которая принимает любое число аргументов) арность лямбда-функции определяется по числу аргументов-массивов. Это корректно для функций высшего порядка, таких как arrayMap, arrayFilter и arrayFold. Для функций высшего порядка, которые помимо массивов принимают фиксированные параметры, не являющиеся массивами, — например, arrayPartialSort(f, limit, arr) — использование имени вариативной функции без явной лямбды может дать неверную арность, и в этом случае требуется явная лямбда-функция.
Вариативные внутренние функции также не выполняют автоматическую распаковку кортежей на входе. Например, arrayMap(concat, [('a', 'b'), ('c', 'd')]) переписывается в унарную лямбда-функцию и не эквивалентно arrayMap((x, y) -> concat(x, y), [('a', 'b'), ('c', 'd')]). Используйте явную лямбда-функцию, если нужно деструктурировать элементы кортежа в вариативный вызов.
Пользовательские функции (UDFs)
ClickHouse поддерживает пользовательские функции. См. UDFs.