Перейти к основному содержанию
Перейти к основному содержанию

Синтаксис

В этом разделе мы рассмотрим синтаксис SQL в ClickHouse. ClickHouse использует синтаксис, основанный на SQL, но предлагает ряд расширений и оптимизаций.

Разбор запросов

В ClickHouse есть два типа парсеров:

  • Полный SQL-парсер (рекурсивный нисходящий парсер).
  • Парсер формата данных (быстрый потоковый парсер).

Полный SQL-парсер используется во всех случаях, кроме запроса INSERT, который использует оба парсера.

Рассмотрим следующий запрос:

INSERT INTO t VALUES (1, 'Hello, world'), (2, 'abc'), (3, 'def')

Как уже упоминалось, запрос INSERT использует оба парсера. Фрагмент INSERT INTO t VALUES разбирается полным парсером, а данные (1, 'Hello, world'), (2, 'abc'), (3, 'def') разбираются парсером формата данных, или быстрым потоковым парсером.

Включение полного парсера

Вы также можете включить полный парсер для данных, используя настройку input_format_values_interpret_expressions.

Когда указанная настройка установлена в 1, ClickHouse сначала пытается разобрать значения с помощью быстрого потокового парсера. Если это не удаётся, ClickHouse пытается использовать полный парсер для данных, обрабатывая их как SQL-выражения.

Данные могут быть в любом формате. При получении запроса сервер помещает в оперативную память не более max_query_size байт запроса (по умолчанию 1 МБ), а остальная часть обрабатывается потоковым парсером. Это позволяет избежать проблем с большими INSERT-запросами, который является рекомендуемым способом вставки данных в ClickHouse.

При использовании формата Values в запросе INSERT может показаться, что данные разбираются так же, как выражения в запросе SELECT, однако это не так. Формат Values гораздо более ограничен.

Оставшаяся часть этого раздела посвящена полному парсеру.

Примечание

Дополнительные сведения о парсерах форматов см. в разделе Форматы.

Пробелы

  • Между синтаксическими конструкциями (включая начало и конец запроса) может быть произвольное количество пробельных символов.
  • К пробельным символам относятся пробел, табуляция, перевод строки, возврат каретки (CR) и разрыв страницы.

Комментарии

ClickHouse поддерживает как комментарии в стиле SQL, так и в стиле C:

  • Комментарии в стиле SQL начинаются с --, #! или # и продолжаются до конца строки. Пробел после -- и #! можно опустить.
  • Комментарии в стиле C записываются между /* и */ и могут быть многострочными. Пробелы также не требуются.

Ключевые слова

Ключевые слова в ClickHouse могут быть чувствительными к регистру или нечувствительными к регистру в зависимости от контекста.

Ключевые слова нечувствительны к регистру, когда они соответствуют:

  • стандарту SQL. Например, SELECT, select и SeLeCt — все корректны.
  • реализации в некоторых популярных СУБД (MySQL или Postgres). Например, DateTime то же самое, что и datetime.
Примечание

Вы можете проверить, является ли имя типа данных чувствительным к регистру, в таблице system.data_type_families.

В отличие от стандартного SQL, все остальные ключевые слова (включая имена функций) чувствительны к регистру.

Кроме того, ключевые слова не являются зарезервированными. Они рассматриваются как ключевые только в соответствующем контексте. Если вы используете идентификаторы с тем же именем, что и ключевые слова, заключайте их в двойные кавычки или обратные кавычки.

Например, следующий запрос является корректным, если таблица table_name содержит столбец с именем "FROM":

SELECT "FROM" FROM table_name

Идентификаторы

Идентификаторы — это:

Идентификаторы могут заключаться в кавычки или быть без кавычек, при этом предпочтителен второй вариант.

Идентификаторы без кавычек должны соответствовать регулярному выражению ^[a-zA-Z_][0-9a-Z_]*$ и не могут совпадать с ключевыми словами. См. таблицу ниже с примерами корректных и некорректных идентификаторов:

Корректные идентификаторыНекорректные идентификаторы
xyz, _internal, Id_with_underscores_123_1x, tom@gmail.com, äußerst_schön

Если вы хотите использовать идентификаторы, совпадающие с ключевыми словами, или хотите использовать в идентификаторах другие символы, заключайте их в двойные кавычки или обратные кавычки, например, "id", `id`.

Примечание

Те же правила экранирования, которые применяются к идентификаторам в кавычках, также применяются к строковым литералам. Подробности см. в разделе String.

Литералы

В ClickHouse литерал — это значение, которое явно задаётся в запросе. Другими словами, это фиксированное значение, которое не изменяется во время выполнения запроса.

Литералы могут быть:

В следующих разделах мы подробно рассмотрим каждый из этих видов.

String

Строковые литералы должны быть заключены в одинарные кавычки. Двойные кавычки не поддерживаются.

Экранирование работает одним из двух способов:

  • с использованием предшествующей одинарной кавычки, когда символ одинарной кавычки ' (и только этот символ) может быть экранирован как '', или
  • с использованием предшествующего обратного слэша с поддерживаемыми управляющими последовательностями, перечисленными в таблице ниже.
Примечание

Обратный слэш теряет своё специальное значение, то есть интерпретируется буквально, если он стоит перед символами, отличными от перечисленных ниже.

Supported EscapeDescription
\xHH8-битный символ, за которым следует любое количество шестнадцатеричных цифр (H).
\Nзарезервировано, ничего не делает (например, SELECT 'a\Nb' возвращает ab)
\aзвуковой сигнал
\bbackspace
\eуправляющий символ Escape
\fперевод страницы
\nперевод строки
\rвозврат каретки
\tгоризонтальная табуляция
\vвертикальная табуляция
\0нулевой символ
\\обратный слэш
\' (или '')одинарная кавычка
\"двойная кавычка
`обратная кавычка (backtick)
\/косая черта (forward slash)
\=знак равенства
ASCII control characters (c <= 31).управляющие символы ASCII (c <= 31).
Примечание

В строковых литералах необходимо как минимум экранировать символы ' и \, используя управляющие последовательности \' (или: '') и \\.

Числовые литералы

Числовые литералы разбираются следующим образом:

  • Если литерал начинается со знака минус -, этот токен пропускается, а знак результата меняется после разбора.
  • Числовой литерал сначала разбирается как 64-битное беззнаковое целое число с использованием функции strtoull.
    • Если значение имеет префикс 0b или 0x/0X, число разбирается как двоичное или шестнадцатеричное соответственно.
    • Если значение отрицательное и абсолютная величина больше 263, возвращается ошибка.
  • Если разбор не удался, значение далее разбирается как число с плавающей запятой с использованием функции strtod.
  • В противном случае возвращается ошибка.

Литералы приводятся к наименьшему типу, в который это значение помещается. Например:

  • 1 разбирается как UInt8
  • 256 разбирается как UInt16.
Важно

Целочисленные значения шире 64 бит (UInt128, Int128, UInt256, Int256) должны быть явно приведены к более крупному типу, чтобы быть корректно разобраны:

-170141183460469231731687303715884105728::Int128
340282366920938463463374607431768211455::UInt128
-57896044618658097711785492504343953926634992332820282019728792003956564819968::Int256
115792089237316195423570985008687907853269984665640564039457584007913129639935::UInt256

Это обходит описанный выше алгоритм и выполняет разбор целого числа с помощью функции, поддерживающей произвольную точность.

В противном случае литерал будет разобран как число с плавающей запятой и, следовательно, может привести к потере точности из‑за усечения.

Дополнительные сведения см. в разделе Data types.

Символы подчеркивания _ внутри числовых литералов игнорируются и могут использоваться для улучшения читаемости.

Поддерживаются следующие числовые литералы:

Числовой литералПримеры
Целые числа1, 10_000_000, 18446744073709551615, 01
Десятичные дроби0.1
Экспоненциальная запись1e100, -1e-100
Числа с плавающей запятой123.456, inf, nan
Шестнадцатеричные числа0xc0fe
Строки в шестнадцатеричном формате, совместимые со стандартом SQLx'c0fe'
Двоичные числа0b1101
Строки в двоичном формате, совместимые со стандартом SQLb'1101'
Примечание

Восьмеричные литералы не поддерживаются, чтобы избежать случайных ошибок интерпретации.

Составные

Массивы создаются с помощью квадратных скобок [1, 2, 3]. Кортежи создаются с помощью круглых скобок (1, 'Hello, world!', 2). Технически это не литералы, а выражения с оператором создания массива и оператором создания кортежа соответственно. Массив должен состоять как минимум из одного элемента, а кортеж — как минимум из двух элементов.

Примечание

Существует отдельный случай, когда кортежи используются в условии IN запроса SELECT. Результаты запроса могут включать кортежи, но кортежи не могут храниться в базе данных (за исключением таблиц, использующих движок Memory).

NULL

NULL используется для обозначения отсутствующего значения. Чтобы хранить NULL в поле таблицы, это поле должно иметь тип Nullable.

Примечание

Следует учитывать следующее о NULL:

  • В зависимости от формата данных (входного или выходного) NULL может иметь разное представление. Дополнительную информацию см. в разделе форматы данных.
  • Обработка NULL имеет особенности. Например, если хотя бы один из аргументов операции сравнения равен NULL, результат этой операции также будет NULL. То же касается умножения, сложения и других операций. Рекомендуем ознакомиться с документацией для каждой операции.
  • В запросах вы можете проверять NULL с помощью операторов IS NULL и IS NOT NULL, а также соответствующих функций isNull и isNotNull.

Heredoc

Heredoc — это способ задать строку (часто многострочную), сохраняя исходное форматирование. Heredoc — это пользовательский строковый литерал, помещённый между двумя символами $.

Например:

SELECT $heredoc$SHOW CREATE VIEW my_view$heredoc$;

┌─'SHOW CREATE VIEW my_view'─┐
│ SHOW CREATE VIEW my_view   │
└────────────────────────────┘
Примечание
  • Содержимое между двумя heredoc-блоками обрабатывается «как есть».
Совет
  • Вы можете использовать heredoc, чтобы вставлять фрагменты кода на SQL, HTML, XML и т. д.

Определение и использование параметров запроса

Параметры запроса позволяют писать универсальные запросы, содержащие абстрактные placeholders вместо конкретных идентификаторов. Когда выполняется запрос с параметрами запроса, все placeholders обрабатываются и заменяются фактическими значениями параметров запроса.

Существует два способа задать параметр запроса:

  • SET param_<name>=<value>
  • --param_<name>='<value>'

Во втором варианте он передаётся как аргумент в clickhouse-client в командной строке, где:

  • <name> — имя параметра запроса.
  • <value> — его значение.

На параметр запроса можно сослаться в запросе с помощью {<name>: <datatype>}, где <name> — имя параметра запроса, а <datatype> — тип данных, к которому он приводится.

Пример с командой SET

Например, следующий SQL задаёт параметры с именами a, b, c и d, каждый со своим типом данных:

SET param_a = 13;
SET param_b = 'str';
SET param_c = '2022-08-04 18:30:53';
SET param_d = {'10': [11, 12], '13': [14, 15]};

SELECT
   {a: UInt32},
   {b: String},
   {c: DateTime},
   {d: Map(String, Array(UInt8))};

13    str    2022-08-04 18:30:53    {'10':[11,12],'13':[14,15]}
Пример с clickhouse-client

Если вы используете clickhouse-client, параметры указываются как --param_name=value. Например, следующий параметр имеет имя message, и он интерпретируется как значение типа String:

clickhouse-client --param_message='hello' --query="SELECT {message: String}"

hello

Если параметр запроса представляет имя базы данных, таблицы, функции или другого идентификатора, используйте тип Identifier. Например, следующий запрос возвращает строки из таблицы с именем uk_price_paid:

SET param_mytablename = "uk_price_paid";
SELECT * FROM {mytablename:Identifier};
Примечание

Параметры запроса не являются универсальным механизмом текстовой подстановки, который можно использовать в произвольных местах произвольных SQL-запросов. Они в первую очередь предназначены для работы в операторах SELECT вместо идентификаторов или литералов.

Функции

Вызовы функций записываются как идентификатор со списком аргументов (возможно, пустым) в круглых скобках. В отличие от стандартного SQL, скобки обязательны даже для пустого списка аргументов. Например:

now()

Также есть:

Некоторые агрегатные функции могут иметь два списка аргументов в скобках. Например:

quantile (0.9)(x) 

Эти агрегатные функции называются параметрическими функциями, а аргументы из первого списка — параметрами.

Примечание

Синтаксис агрегатных функций без параметров совпадает с синтаксисом обычных функций.

Операторы

Операторы во время разбора запроса преобразуются в соответствующие функции с учётом их приоритета и ассоциативности.

Например, выражение

1 + 2 * 3 + 4

преобразуется в

plus(plus(1, multiply(2, 3)), 4)`

Типы данных и движки таблиц базы данных

Типы данных и движки таблиц в запросе CREATE указываются так же, как идентификаторы или функции. Другими словами, они могут как содержать список аргументов в скобках, так и не содержать его.

Для получения дополнительной информации см. разделы:

Expressions

Выражением может быть любой из следующих типов:

  • функция
  • идентификатор
  • литерал
  • применение оператора
  • выражение в скобках
  • подзапрос
  • звёздочка (*)

Оно также может содержать псевдоним.

Список выражений — это одно или несколько выражений, разделённых запятыми. Функции и операторы, в свою очередь, могут иметь выражения в качестве аргументов.

Константное выражение — это выражение, результат которого известен во время анализа запроса, то есть до выполнения. Например, выражения, состоящие из литералов, являются константными выражениями.

Псевдонимы выражений

Псевдоним — это определяемое пользователем имя для выражения в запросе.

expr AS alias

Части приведённого выше синтаксиса описаны ниже.

Элемент синтаксисаОписаниеПримерПримечания
ASКлючевое слово для определения псевдонимов. В операторе SELECT можно задать псевдоним для имени таблицы или имени столбца и без использования ключевого слова AS.SELECT table_name_alias.column_name FROM table_name table_name_alias.В функции CAST ключевое слово AS имеет иное значение. См. описание функции.
exprЛюбое выражение, поддерживаемое ClickHouse.SELECT column_name * 2 AS double FROM some_table
aliasИмя для expr. Псевдонимы должны соответствовать синтаксису идентификаторов.SELECT "table t".column_name FROM table_name AS "table t".

Примечания по использованию

  • Псевдонимы действуют в пределах всего запроса или подзапроса, и вы можете задать псевдоним в любой части запроса для любого выражения. Например:
SELECT (1 AS n) + 2, n`.
  • Псевдонимы не видны в подзапросах и между подзапросами. Например, при выполнении следующего запроса ClickHouse выдаёт исключение Unknown identifier: num:
`SELECT (SELECT sum(b.a) + num FROM b) - a.a AS num FROM a`
  • Если для результирующих столбцов в предложении SELECT подзапроса определены псевдонимы, эти столбцы доступны во внешнем запросе. Например:
SELECT n + m FROM (SELECT 1 AS n, 2 AS m)`.
  • Будьте осторожны с псевдонимами, совпадающими с именами столбцов или таблиц. Рассмотрим следующий пример:
CREATE TABLE t
(
    a Int,
    b Int
)
ENGINE = TinyLog();

SELECT
    argMax(a, b),
    sum(b) AS b
FROM t;

Получено исключение от сервера (версия 18.14.17):
Code: 184. DB::Exception: Received from localhost:9000, 127.0.0.1. DB::Exception: Агрегатная функция sum(b) обнаружена внутри другой агрегатной функции в запросе.

В предыдущем примере мы объявили таблицу t со столбцом b. Затем при выборке данных мы задали псевдоним sum(b) AS b. Поскольку псевдонимы являются глобальными, ClickHouse заменил литерал b в выражении argMax(a, b) выражением sum(b). Эта замена привела к возникновению исключения.

Примечание

Вы можете изменить это поведение по умолчанию, установив prefer_column_name_to_alias в значение 1.

Звёздочка

В запросе SELECT звёздочка может использоваться вместо выражения. Дополнительные сведения см. в разделе SELECT.