Nesta seção, vamos examinar a sintaxe SQL do ClickHouse. O ClickHouse usa uma sintaxe baseada em SQL, mas oferece diversas extensões e otimizações.
Análise sintática de consultas
Há dois tipos de parsers no ClickHouse:
- Um parser SQL completo (um parser por descida recursiva).
- Um parser de formato de dados (um parser de fluxo rápido).
O parser SQL completo é usado em todos os casos, exceto na consulta INSERT, que usa ambos os parsers.
Vamos examinar a consulta abaixo:
INSERT INTO t VALUES (1, 'Hello, world'), (2, 'abc'), (3, 'def')Como já mencionado, a consulta INSERT usa ambos os parsers.
O fragmento INSERT INTO t VALUES é analisado pelo parser completo,
e os dados (1, 'Hello, world'), (2, 'abc'), (3, 'def') são analisados pelo parser de formato de dados, ou parser rápido de fluxo.
Ativando o parser completo
Você também pode ativar o parser completo para os dados
usando a configuração input_format_values_interpret_expressions.
Quando a configuração mencionada acima é definida como 1,
o ClickHouse primeiro tenta analisar os valores com o parser rápido de fluxo.
Se isso falhar, o ClickHouse tenta usar o parser completo para os dados, tratando-os como uma expressão SQL.
Os dados podem estar em qualquer formato.
Quando uma consulta é recebida, o servidor mantém no máximo max_query_size bytes da solicitação em RAM
(por padrão, 1 MB), e o restante é analisado em fluxo.
Isso ajuda a evitar problemas com consultas INSERT grandes, que é a forma recomendada de inserir seus dados no ClickHouse.
Ao usar o formato Values em uma consulta INSERT,
pode parecer que os dados são analisados da mesma forma que as expressões em uma consulta SELECT, mas não é esse o caso.
O formato Values é muito mais limitado.
O restante desta seção aborda o parser completo.
Espaços
- Pode haver qualquer quantidade de caracteres de espaço entre construções sintáticas (inclusive no início e no fim de uma consulta).
- Os caracteres de espaço incluem espaço, tabulação, quebra de linha, CR e avanço de página.
O ClickHouse oferece suporte a comentários no estilo SQL e no estilo C:
- Comentários no estilo SQL começam com
--,#!ou#e vão até o fim da linha. O espaço após--e#!pode ser omitido. - Comentários no estilo C:
//(ou mais de 2 caracteres/) seguido de texto até o fim da linha. Não é necessário espaço após/.- Podem ir de
/*a*/para comentários de várias linhas. Também não é necessário espaço. - Comentários no estilo C podem ser aninhados.
Por exemplo:
/*
* Calcula o número de dias entre duas datas.
* /* Retorna NULL se algum dos argumentos for NULL */
*/
SELECT
dateDiff('day', toDate('2024-01-01'), toDate('2024-12-31')) AS days_in_year, -- 365
dateDiff('day', toDate('2020-01-01'), today()) AS days_since #! desde 2020
///////////////////////////////////////////////////////////////////
# TODO: adicionar variantes de hora/minutoPalavras-chave
As palavras-chave no ClickHouse podem ser sensíveis a maiúsculas e minúsculas ou não sensíveis a maiúsculas e minúsculas, dependendo do contexto.
As palavras-chave não diferenciam maiúsculas de minúsculas quando correspondem a:
- ao padrão SQL. Por exemplo,
SELECT,selecteSeLeCtsão todos válidos. - à implementação de alguns SGBDs populares (MySQL ou Postgres). Por exemplo,
DateTimeé o mesmo quedatetime.
Ao contrário do SQL padrão, todas as outras palavras-chave (incluindo nomes de funções) são sensíveis a maiúsculas e minúsculas.
Além disso, as palavras-chave não são reservadas. Elas só são tratadas como tal no contexto correspondente. Se você usar identificadores com o mesmo nome das palavras-chave, coloque-os entre aspas duplas ou backticks.
Por exemplo, a consulta a seguir é válida se a tabela table_name tiver uma coluna com o nome "FROM":
SELECT "FROM" FROM table_nameIdentificadores
Os identificadores são:
- Nomes de cluster, database, tabela, partição e coluna.
- Funções.
- Tipos de dados.
- Aliases de expressão.
Os identificadores podem ser colocados entre aspas ou não, embora a segunda opção seja preferível.
Identificadores sem aspas devem corresponder à regex ^[a-zA-Z_][0-9a-zA-Z_]*$ e não podem ser iguais a palavras-chave.
Veja a tabela abaixo com exemplos de identificadores válidos e inválidos:
| Identificadores válidos | Identificadores inválidos |
|---|---|
xyz, _internal, Id_with_underscores_123_ |
1x, tom@gmail.com, äußerst_schön |
Se você quiser usar identificadores iguais a palavras-chave ou usar outros símbolos em identificadores, coloque-os entre aspas duplas ou backticks, por exemplo, "id", `id`.
Literais
No ClickHouse, um literal é um valor representado diretamente em uma consulta. Em outras palavras, é um valor fixo que não se altera durante a execução da consulta.
Os literais podem ser:
A seguir, examinamos cada um deles em mais detalhes nas seções abaixo.
String
Literais de string devem estar entre aspas simples. Aspas duplas não são aceitas.
O escape funciona de uma destas formas:
- usando uma aspa simples antes, em que o caractere de aspas simples
'(e somente esse caractere) pode ser escapado como'', ou - usando uma barra invertida antes, com as seguintes sequências de escape compatíveis listadas na tabela abaixo.
| Escape compatível | Descrição |
|---|---|
\xHH |
Especificação de caractere de 8 bits seguida por qualquer quantidade de dígitos hexadecimais (H). |
\N |
reservado, não faz nada (por exemplo, SELECT 'a\Nb' retorna ab) |
\a |
alerta |
\b |
retrocesso |
\e |
caractere de escape |
\f |
avanço de página |
\n |
quebra de linha |
\r |
retorno de carro |
\t |
tabulação horizontal |
\v |
tabulação vertical |
\0 |
caractere nulo |
\\ |
barra invertida |
\' (ou '') |
aspas simples |
\" |
aspas duplas |
` |
acento grave |
\/ |
barra normal |
\= |
sinal de igual |
| Caracteres de controle ASCII (c <= 31). |
Numérico
Os literais numéricos são analisados da seguinte forma:
- Se o literal for precedido por um sinal de menos
-, o token será ignorado e o resultado será negado após a análise. - O literal numérico é analisado primeiro como um inteiro sem sinal de 64 bits, usando a função strtoull.
- Se o valor tiver o prefixo
0bou0x/0X, o número será analisado como binário ou hexadecimal, respectivamente. - Se o valor for negativo e sua magnitude absoluta for maior que 263, um erro será retornado.
- Se o valor tiver o prefixo
- Se isso não funcionar, o valor será então analisado como um número de ponto flutuante usando a função strtod.
- Caso contrário, um erro será retornado.
Os valores literais são convertidos para o menor tipo no qual o valor cabe. Por exemplo:
1é analisado comoUInt8256é analisado comoUInt16.
Para mais informações, consulte Tipos de dados.
Os sublinhados _ dentro de literais numéricos são ignorados e podem ser usados para melhorar a legibilidade.
Há suporte aos seguintes literais numéricos:
| Literal numérico | Exemplos |
|---|---|
| Inteiros | 1, 10_000_000, 18446744073709551615, 01 |
| Decimais | 0.1 |
| Notação exponencial | 1e100, -1e-100 |
| Números de ponto flutuante | 123.456, inf, nan |
| Hexadecimal | 0xc0fe |
| String hexadecimal compatível com SQL Standard | x'c0fe' |
| Binário | 0b1101 |
| String binária compatível com SQL Standard | b'1101' |
Compostos
Arrays são construídos com []: [1, 2, 3]. Tuplas são construídas com (): (1, 'Hello, world!', 2).
Tecnicamente, eles não são literais, mas expressões com o operador de criação de array e o operador de criação de tupla, respectivamente.
Um array deve consistir em pelo menos um item, e uma tupla deve ter pelo menos dois itens.
NULL
NULL é usado para indicar que um valor está ausente.
Para armazenar NULL em um campo de uma tabela, ele deve ser do tipo Nullable.
Heredoc
Um heredoc é uma forma de definir uma string (geralmente em várias linhas), mantendo a formatação original.
Um heredoc é definido como um literal de string personalizado, colocado entre dois símbolos $.
Por exemplo:
SELECT $heredoc$SHOW CREATE VIEW my_view$heredoc$;
┌Definição e uso de parâmetros de consulta
Os parâmetros de consulta permitem escrever consultas genéricas que contêm placeholders abstratos em vez de identificadores concretos. Quando uma consulta com parâmetros é executada, todos os placeholders são resolvidos e substituídos pelos valores reais dos parâmetros de consulta.
Os parâmetros de consulta podem ser definidos de várias formas:
SET param_<name>=<value>— usando um comandoSETem uma consulta.--param_<name>='<value>'— como argumento para oclickhouse-clientna linha de comando.param_<name>=<value>— como parâmetro de consulta na URL da interface HTTP.
Um parâmetro de consulta pode ser referenciado em uma consulta usando {<name>: <datatype>}, em que <name> é o nome do parâmetro de consulta e <datatype> é o tipo de dado para o qual ele será convertido.
Exemplo com o comando SET
Por exemplo, o SQL a seguir define parâmetros chamados a, b, c e d — cada um com um tipo de dado diferente:
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]}Exemplo com clickhouse-client
Se você estiver usando o clickhouse-client, os parâmetros serão especificados como --param_name=value. Por exemplo, o parâmetro a seguir tem o nome message e é recuperado como String:
clickhouse-client --param_message='hello' --query="SELECT {message: String}"
helloSe o parâmetro de consulta representar o nome de um banco de dados, tabela, função ou outro identificador, use Identifier como tipo. Por exemplo, a consulta a seguir retorna linhas de uma tabela chamada uk_price_paid:
SET param_mytablename = "uk_price_paid";
SELECT * FROM {mytablename:Identifier};Exemplo com a interface HTTP
Os parâmetros de consulta podem ser passados como parâmetros de consulta na URL com o prefixo param_. Por exemplo:
curl -s "http://localhost:8123/?param_message=hello" --data-binary "SELECT {message: String}"
helloExemplo com a interface web
A interface web integrada (play.html) detecta automaticamente placeholders de parâmetro no formato {name:Type} na consulta e exibe campos de entrada identificados para cada parâmetro. Os valores dos parâmetros são incluídos na solicitação HTTP e também persistidos na URL da página para permitir favoritos e compartilhamento.
Funções
Chamadas de função são escritas como um identificador seguido de uma lista de argumentos (possivelmente vazia) entre ().
Ao contrário do SQL padrão, os parênteses são obrigatórios, mesmo para uma lista de argumentos vazia.
Por exemplo:
now()Há também:
Algumas funções de agregação podem conter duas listas de argumentos entre parênteses. Por exemplo:
quantile (0.9)(x) Essas funções de agregação são chamadas de funções "paramétricas", e os argumentos da primeira lista são chamados de "parâmetros".
Operadores
Os operadores são convertidos nas funções correspondentes durante a análise sintática da consulta, levando em conta sua prioridade e associatividade.
Por exemplo, a expressão
1 + 2 * 3 + 4é convertido em
plus(plus(1, multiply(2, 3)), 4)`Tipos de dados e motores de tabela do banco de dados
Os tipos de dados e os motores de tabela na consulta CREATE são escritos da mesma forma que identificadores ou funções.
Em outras palavras, eles podem ou não conter uma lista de argumentos entre parênteses.
Para mais informações, consulte as seções:
Expressões
Uma expressão pode ser qualquer um dos itens a seguir:
- uma função
- um identificador
- um literal
- a aplicação de um operador
- uma expressão entre parênteses
- uma subconsulta
- um asterisco
Ela também pode conter um alias.
Uma lista de expressões consiste em uma ou mais expressões separadas por vírgulas. Funções e operadores, por sua vez, podem ter expressões como argumentos.
Uma expressão constante é uma expressão cujo resultado é conhecido durante a análise da consulta, isto é, antes da execução. Por exemplo, expressões com literais são expressões constantes.
Aliases de expressão
Um alias é um nome atribuído pelo usuário a uma expressão em uma consulta.
expr AS aliasAs partes da sintaxe acima são explicadas abaixo.
| Parte da sintaxe | Descrição | Exemplo | Observações |
|---|---|---|---|
AS |
A palavra-chave usada para definir aliases. Você pode definir o alias de um nome de tabela ou de uma coluna em uma cláusula SELECT sem usar a palavra-chave AS. |
SELECT table_name_alias.column_name FROM table_name table_name_alias. |
Na função CAST, a palavra-chave AS tem outro significado. Consulte a descrição da função. |
expr |
Qualquer expressão suportada pelo ClickHouse. | SELECT column_name * 2 AS double FROM some_table |
|
alias |
Nome de expr. Os aliases devem seguir a sintaxe de identificadores. |
SELECT "table t".column_name FROM table_name AS "table t". |
Notas de uso
- Aliases são globais em uma consulta ou subconsulta, e você pode definir um alias em qualquer parte da consulta para qualquer expressão. Por exemplo:
SELECT (1 AS n) + 2, n`.- Aliases não ficam visíveis em subconsultas nem entre subconsultas. Por exemplo, ao executar a consulta a seguir, ClickHouse gera a exceção
Unknown identifier: num:
`SELECT (SELECT sum(b.a) + num FROM b) - a.a AS num FROM a`- Se um alias for definido para as colunas de resultado na cláusula
SELECTde uma subconsulta, essas colunas ficam visíveis na consulta externa. Por exemplo:
SELECT n + m FROM (SELECT 1 AS n, 2 AS m)`.- Tenha cuidado com aliases que sejam iguais a nomes de colunas ou tabelas. Vamos considerar o exemplo a seguir:
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.No exemplo anterior, declaramos a tabela t com a coluna b.
Em seguida, ao selecionar os dados, definimos o alias sum(b) AS b.
Como os aliases têm escopo global,
ClickHouse substituiu o literal b na expressão argMax(a, b) pela expressão sum(b).
Essa substituição causou a exceção.
Asterisco
Em uma consulta SELECT, um asterisco pode substituir a expressão.
Para mais informações, consulte a seção SELECT.
Comentários