语法
在本节中,我们将了解 ClickHouse 的 SQL 语法。ClickHouse 使用基于 SQL 的语法,但提供了一些扩展和优化。
查询解析
ClickHouse 中有两种类型的解析器
- 完整的 SQL 解析器(递归下降解析器)。
- 数据格式解析器(快速流式解析器)。
完整的 SQL 解析器用于除 INSERT
查询之外的所有情况,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 表达式。
数据可以具有任何格式。当收到查询时,服务器在 RAM 中计算不超过 max_query_size 字节的请求(默认情况下为 1 MB),其余部分将进行流式解析。这样做是为了避免大型 INSERT
查询出现问题,这是在 ClickHouse 中插入数据的推荐方式。
当在 INSERT
查询中使用 Values
格式时,数据可能看起来与 SELECT
查询中表达式的解析方式相同,但事实并非如此。Values
格式的限制更多。
本节的其余部分涵盖了完整解析器。
有关格式解析器的更多信息,请参阅 格式 部分。
空格
- 在语法结构之间(包括查询的开头和结尾)可以有任意数量的空格符号。
- 空格符号包括空格、制表符、换行符、CR 和换页符。
注释
ClickHouse 支持 SQL 风格和 C 风格的注释
- SQL 风格的注释以
--
、#!
或#
开头,并持续到行尾。--
和#!
后的空格可以省略。 - C 风格的注释从
/*
跨越到*/
,并且可以是多行的。空格也不是必需的。
关键字
ClickHouse 中的关键字可以是区分大小写或不区分大小写,具体取决于上下文。
当关键字与以下内容对应时,不区分大小写
- SQL 标准。例如,
SELECT
、select
和SeLeCt
都是有效的。 - 在一些流行的 DBMS(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 、[email protected] 、äußerst_schön |
如果您想使用与关键字相同的标识符,或者想在标识符中使用其他符号,请使用双引号或反引号将其引起来,例如,"id"
、`id`
。
应用于带引号标识符中转义的相同规则也适用于字符串字面量。有关更多详细信息,请参阅 字符串。
字面量
在 ClickHouse 中,字面量是直接在查询中表示的值。换句话说,它是在查询执行期间不会更改的固定值。
字面量可以是
我们将在下面的章节中更详细地了解其中的每一个。
字符串
字符串字面量必须用单引号括起来。不支持双引号。
转义可以通过以下两种方式实现
- 使用前导单引号,其中单引号字符
'
(且仅此字符)可以转义为''
,或者 - 使用前导反斜杠以及下表中列出的以下支持的转义序列。
反斜杠会失去其特殊含义,即如果它位于以下列出的字符之外的其他字符之前,则按字面意思解释。
支持的转义 | 描述 |
---|---|
\xHH | 8 位字符规范,后跟任意数量的十六进制数字 (H)。 |
\N | 保留,不执行任何操作(例如 SELECT 'a\Nb' 返回 ab ) |
\a | 警报 |
\b | 退格 |
\e | 转义字符 |
\f | 换页符 |
\n | 换行符 |
\r | 回车符 |
\t | 水平制表符 |
\v | 垂直制表符 |
\0 | \0 |
\\ | 空字符 |
\\ | 反斜杠 |
\" | \' (或 '' ) |
` | 单引号 |
\/ | \" |
\= | 双引号 |
\` |
反引号
\/
正斜杠
\=
- 等号
- ASCII 控制字符 (c <= 31)。
- 在字符串字面量中,您至少需要使用转义码
\'
(或:''
)和\\
来转义'
和\
。
数值
- 数值字面量按如下方式解析
- 首先,作为 64 位有符号数,使用 strtoull 函数。
如果失败,则作为 64 位无符号数,使用 strtoll 函数。
如果失败,则作为浮点数,使用 strtod 函数。
否则,返回错误。
字面量值被强制转换为值适合的最小类型。例如 | 1 解析为 UInt8 |
---|---|
256 解析为 UInt16 。 | 1 , 10_000_000 , 18446744073709551615 , 01 |
有关更多信息,请参阅 数据类型。 | 0.1 |
数值字面量中的下划线 _ 会被忽略,并且可以用于提高可读性。 | 支持以下数值字面量 |
数值字面量 | 示例 |
整数 | 十进制数 |
指数表示法 |
|
浮点数 |
|
十六进制 |
|
SQL 标准兼容的十六进制字符串
x'c0fe'
二进制
0b1101
SQL 标准兼容的二进制字符串
b'1101'
NULL
NULL
用于指示值缺失。要在表字段中存储 NULL
,它必须是 Nullable 类型。
应注意以下关于 NULL
的事项
SELECT $heredoc$SHOW CREATE VIEW my_view$heredoc$;
┌─'SHOW CREATE VIEW my_view'─┐
│ SHOW CREATE VIEW my_view │
└────────────────────────────┘
- 根据数据格式(输入或输出),
NULL
可能具有不同的表示形式。有关更多信息,请参阅 数据格式。
NULL
处理非常细致。例如,如果比较运算的至少一个参数为 NULL
,则此运算的结果也为 NULL
。乘法、加法和其他运算也是如此。我们建议阅读每个运算的文档。- 在查询中,您可以使用
IS NULL
和IS NOT NULL
运算符以及相关的函数isNull
和isNotNull
来检查NULL
。
Heredoc
Heredoc 是一种定义字符串(通常是多行)的方式,同时保持原始格式。Heredoc 被定义为自定义字符串字面量,放置在两个 $
符号之间。
例如
两个 heredoc 之间的值按“原样”处理。
提示
您可以使用 heredoc 嵌入 SQL、HTML 或 XML 代码片段等。
- 定义和使用查询参数
- 查询参数允许您编写通用查询,其中包含抽象占位符而不是具体的标识符。当执行带有查询参数的查询时,所有占位符都会被解析并替换为实际的查询参数值。
定义查询参数有两种方法
SET param_<name>=<value>
--param_<name>='<value>'
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
,其中
<name>
是查询参数的名称。
clickhouse-client --param_message='hello' --query="SELECT {message: String}"
hello
<value>
是其值。
SET param_mytablename = "uk_price_paid";
SELECT * FROM {mytablename:Identifier};
可以使用 {<name>: <datatype>}
在查询中引用查询参数,其中 <name>
是查询参数名称,<datatype>
是它转换成的数据类型。
使用 SET 命令的示例
例如,以下 SQL 定义了名为 a
、b
、c
和 d
的参数 - 每个参数都具有不同的数据类型
now()
使用 clickhouse-client 的示例
- 如果您正在使用
clickhouse-client
,则参数指定为--param_name=value
。例如,以下参数的名称为message
,它作为String
检索. - 如果查询参数表示数据库、表、函数或其他标识符的名称,请使用
Identifier
作为其类型。例如,以下查询从名为uk_price_paid
的表中返回行.
查询参数不是通用的文本替换,不能在任意 SQL 查询的任意位置使用。它们主要设计用于 SELECT
语句中,代替标识符或字面量。
quantile (0.9)(x)
函数
函数调用像标识符一样编写,并在圆括号中包含参数列表(可能为空)。与标准 SQL 相反,即使对于空参数列表,也需要使用括号。例如
还有
常规函数
聚合函数
1 + 2 * 3 + 4
某些聚合函数可以在括号中包含两个参数列表。例如
plus(plus(1, multiply(2, 3)), 4)`
这些聚合函数称为“参数化”函数,第一个列表中的参数称为“参数”。
不带参数的聚合函数的语法与常规函数相同。
运算符
被转换为
数据类型和数据库表引擎
CREATE
查询中的数据类型和表引擎的编写方式与标识符或函数相同。换句话说,它们可能包含也可能不包含括号中的参数列表。- 有关更多信息,请参阅以下部分
- 表引擎
- CREATE
- 表达式
- 表达式可以是以下内容
- 函数
标识符
字面量
运算符的应用
括号中的表达式
expr AS alias
子查询
或星号。 | 描述 | 它也可以包含 别名。 | 表达式列表是由逗号分隔的一个或多个表达式。函数和运算符反过来可以将表达式作为参数。 |
---|---|---|---|
表达式别名 | 别名是查询中 表达式 的用户定义名称。 | 上面语法的各个部分在下面进行了解释。 . | 语法部分 |
示例 | 注释 | AS | |
用于定义别名的关键字。您可以为 | SELECT table_name_alias.column_name FROM table_name table_name_alias | 在 CAST 函数中, . |
expr
- ClickHouse 支持的任何表达式。
SELECT (1 AS n) + 2, n`.
- SELECT column_name * 2 AS double FROM some_table
`SELECT (SELECT sum(b.a) + num FROM b) - a.a AS num FROM a`
- alias
SELECT n + m FROM (SELECT 1 AS n, 2 AS m)`.
expr
的名称。别名应符合 标识符 语法。
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.
SELECT "table t".column_name FROM table_name AS "table t"
使用注意事项
别名对于查询或子查询是全局的,您可以在查询的任何部分为任何表达式定义别名。例如
别名在子查询之间和子查询中不可见。例如,当执行以下查询时,ClickHouse 会生成异常 Unknown identifier: num