SELECT-запросом может следовать цепочка пайп-операторов. Каждый оператор начинается с токена |>, принимает результат предыдущего запроса в качестве входных данных и применяет к нему ещё одно преобразование. Внутри каждого оператора используется обычный синтаксис ClickHouse.
Пайп-операторы — это расширение синтаксиса: каждый оператор оборачивает предыдущий запрос в подзапрос, поэтому получающееся AST совпадает с AST эквивалентного запроса с вложенными подзапросами, а приведённый выше запрос эквивалентен следующему:
Запросы с FROM
Запрос может начинаться с предложенияFROM, а предложение SELECT в таких запросах необязательно: если оно опущено, запрос выполняется так, как если бы было указано SELECT *:
AS или без него, как в предложении FROM обычного SELECT-запроса: FROM orders o WHERE o.amount > 100. Единственное исключение — псевдоним в виде отдельного слова select: после таблиц оно начинает явное предложение SELECT, а не считается псевдонимом. Таблица с именем select не подпадает под это правило и сохраняет свой псевдоним: FROM select s WHERE s.id = 1.
Подзапрос в скобках также может начинаться с предложения FROM, из-за чего запись (from IN ('a')) становится неоднозначной: она читается либо как выражение from IN ('a') над столбцом с именем from, либо как подзапрос SELECT * FROM IN('a') над табличной функцией с именем IN. Прочтение со столбцом более давнее, и приоритет отдаётся ему: скобки, содержимое которых читается как выражение, начинающееся со слова from, за которым следует оператор, всегда являются этим выражением, а не подзапросом. Чтобы получить другое прочтение, укажите предложение SELECT явно: 1 IN (SELECT * FROM in).
Предложение SELECT нельзя опускать, если смещение выборки последней таблицы также может быть интерпретировано как OFFSET на уровне запроса, поскольку в FROM t SAMPLE 1/10 OFFSET 5 OFFSET относится к SAMPLE, а в FROM t SAMPLE 1/10 SELECT * OFFSET 5 это OFFSET на уровне запроса — явное предложение SELECT необходимо для устранения неоднозначности. Если запрос продолжается предложением, перед которым OFFSET на уровне запроса не может стоять, неоднозначность отсутствует и предложение SELECT, как обычно, необязательно: FROM t SAMPLE 1/10 OFFSET 5 WHERE x > 0, FROM t SAMPLE 1/10 OFFSET 5 JOIN dim USING (id).
Операторы
WHERE
|> WHERE condition фильтрует входные строки. При применении после агрегации работает как HAVING:
SELECT
|> SELECT [DISTINCT] expr1 [AS alias1], ... оставляет в выходных данных только перечисленные столбцы выражений:
SELECT обычного запроса: за ней может следовать конец запроса или следующий оператор |>: FROM orders |> SELECT customer, amount, |> LIMIT 1. То же относится к операторам EXTEND и AGGREGATE.
EXTEND
|> EXTEND expr1 [AS alias1], ... добавляет перечисленные выражения к входным столбцам; это эквивалентно SELECT *, expr1 AS alias1, ...:
SET
|> SET column1 = expr1, ... заменяет значения указанных столбцов; эквивалентно SELECT * REPLACE (expr1 AS column1, ...):
DROP
|> DROP column1, ... удаляет указанные столбцы; эквивалентно SELECT * EXCEPT (column1, ...):
AS
|> AS alias присваивает псевдоним входным данным следующего оператора, чтобы на них можно было ссылаться в этом операторе. Это особенно полезно при JOIN:
AGGREGATE
|> AGGREGATE agg1 [AS alias1], ... [GROUP BY expr1 [AS alias1], ...] агрегирует входные строки. Выходные столбцы: сначала столбцы группировки, затем агрегатные столбцы. Без GROUP BY все входные строки агрегируются в одну строку:
DISTINCT
|> DISTINCT удаляет дублирующиеся строки; это эквивалентно SELECT DISTINCT *.
ORDER BY
|> ORDER BY expr1 [ASC/DESC], ... сортирует входные строки. Поддерживается полный синтаксис предложения ORDER BY, включая ORDER BY ALL, WITH FILL и INTERPOLATE:
LIMIT и OFFSET
|> LIMIT length [OFFSET offset] и |> OFFSET offset ограничивают число строк:
JOIN и ARRAY JOIN
|> [GLOBAL] [ANY/ALL/ASOF/SEMI/ANTI] [INNER/LEFT/RIGHT/FULL/CROSS] JOIN table [ON expr | USING (columns)] объединяет входные данные с другой таблицей, подзапросом или табличной функцией. Поддерживаются все виды JOIN и ARRAY JOIN, при этом один оператор может содержать несколько JOIN, как и предложение FROM:
ON). Последующие операторы видят объединённые столбцы результата JOIN, как после SELECT *.
Также поддерживается запись CROSS JOIN через запятую, при которой входные данные оператора выступают в качестве левой части: FROM customers |> AS c |> , orders. Как и для других JOIN, входным данным требуется псевдоним, если включена настройка joined_subquery_requires_alias (по умолчанию она включена).
Как и в предложении FROM обычного запроса, JOIN через запятую (CROSS JOIN) не поддерживается непосредственно после ARRAY JOIN: запятая после ARRAY JOIN всегда относится к списку его выражений.
UNION, INTERSECT и EXCEPT
|> UNION [ALL/DISTINCT] (query1) [, (query2), ...], |> INTERSECT [ALL/DISTINCT] ... и |> EXCEPT [ALL/DISTINCT] ... объединяют входные данные с результатами других запросов:
Примечания
- Предложение
WITHзапроса остаётся видимым во всех последующих пайп-операторах — как для скалярных псевдонимов, так и для CTE:WITH 10 AS threshold FROM t |> WHERE x < threshold. - В
INSERT ... SELECTпредложениеWITH, указанное передINSERT, присоединяется к самому внешнему сгенерированномуSELECTи при интерпретации становится доступным внутренним стадиям конвейера через настройкуenable_global_with_statement(включена по умолчанию) — так же, как и во вложенном подзапросе, написанном вручную. Если эта настройка отключена, псевдонимы и CTE изWITH, ограниченного областью действияINSERT, недоступны внутри стадий конвейера — точно так же, как и внутри подзапроса, написанного вручную. - Как и любой
SELECT-запрос, запрос, сгенерированный пайп-оператором, может заканчиваться предложениемSETTINGS, которое присоединяется к этому сгенерированному запросу:FROM t |> LIMIT 1 SETTINGS max_threads = 1эквивалентенSELECT * FROM (SELECT * FROM t) LIMIT 1 SETTINGS max_threads = 1. Это также работает там, где нет отдельного этапа обработки настроек запроса, например в подзапросе, вCREATE VIEWили в табличной функцииview. ПредложениеSETTINGSв середине цепочки остаётся на своей стадии, которая становится подзапросом для следующего оператора. После операции над множествами с операндом в скобках завершающее предложениеSETTINGSне допускается — эквивалентный запрос с подзапросами также не может содержать предложениеSETTINGSв этой позиции. - Предложение
SETTINGSзапроса перед первым пайп-оператором остаётся в этом запросе, который становится подзапросом сгенерированной обёртки. Обычные настройки продолжают работать, поскольку настройки подзапроса применяются при его интерпретации. - Пайп-операторы применяются ко всему предшествующему запросу, включая операции над множествами: в
SELECT 1 UNION ALL SELECT 2 |> AGGREGATE count()агрегация применяется к результатуUNION ALL. Чтобы продолжить запрос сUNIONпосле пайп-оператора, используйте оператор|> UNIONили скобки. - Пайп-операторы можно использовать везде, где ожидается
SELECT-запрос: в подзапросах, вINSERT ... SELECT(включая формуINSERT INTO t FROM src |> ...), вCREATE VIEW, в табличной функцииviewи так далее. - Отдельный оператор для переименования столбцов на месте не предусмотрен; используйте
|> SELECT * EXCEPT (old_name), old_name AS new_nameили операторыSETиDROP.