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

Синтаксис

В этом разделе мы рассмотрим синтаксис 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 гораздо более ограничен.

В остальной части этого раздела рассматривается полный парсер.

Примечание

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

Пробельные символы

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

Комментарии

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-zA-Z_]*$ и не могут совпадать с ключевыми словами. Примеры допустимых и недопустимых идентификаторов приведены в таблице ниже:

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

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

Примечание

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

Литералы

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

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

Рассмотрим каждый из них более подробно в разделах ниже.

Строковые

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

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

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

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

Поддерживаемая escape-последовательностьОписание
\xHHСпецификация 8-битного символа, за которой следует любое количество шестнадцатеричных цифр (H).
\Nзарезервировано, ничего не делает (например, SELECT 'a\Nb' возвращает ab)
\aсигнал
\bвозврат на один символ
\eсимвол escape
\fперевод страницы
\nперевод строки
\rвозврат каретки
\tгоризонтальная табуляция
\vвертикальная табуляция
\0нулевой символ
\\обратная косая черта
\' (или '')одинарная кавычка
\"двойная кавычка
`обратная кавычка
\/прямая косая черта
\=знак равенства
Управляющие символы ASCII (c <= 31).
Примечание

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

Числовые

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

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

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

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

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

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

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

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

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

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

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

Числовой литералПримеры
Целые числа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 и т. д.

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

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

Существует два способа определения параметра запроса:

  • 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 записываются так же, как идентификаторы или функции. Иными словами, они могут содержать или не содержать список аргументов в скобках.

Дополнительную информацию см. в разделах:

Выражения

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

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

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

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

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

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

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

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;

Received exception from server (version 18.14.17):
Code: 184. DB::Exception: Received from localhost:9000, 127.0.0.1. DB::Exception: Aggregate function sum(b) is found inside another aggregate function in query.

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

Примечание

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

Звездочка

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