跳到主要内容
跳到主要内容

语法

在本节中,我们将了解 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 标准。例如,SELECTselectSeLeCt 都是有效的。
  • 在一些流行的 DBMS(MySQL 或 Postgres)中的实现。例如,DateTimedatetime 相同。
注意

您可以在 system.data_type_families 表中检查数据类型名称是否区分大小写。

与标准 SQL 相反,所有其他关键字(包括函数名称)都是 区分大小写的。

此外,关键字不是保留字。仅在相应的上下文中才将其视为关键字。如果您使用与关键字同名的 标识符,请将其括在双引号或反引号中。

例如,如果表 table_name 具有名为 "FROM" 的列,则以下查询是有效的

SELECT "FROM" FROM table_name

标识符

标识符是

标识符可以是带引号的或不带引号的,尽管后者是首选。

不带引号的标识符必须匹配正则表达式 ^[a-zA-Z_][0-9a-zA-Z_]*$ 并且不能等于 关键字。请参阅下表,了解有效和无效标识符的示例

有效标识符无效标识符
xyz_internalId_with_underscores_123_1x[email protected]äußerst_schön

如果您想使用与关键字相同的标识符,或者想在标识符中使用其他符号,请使用双引号或反引号将其引起来,例如,"id"`id`

注意

应用于带引号标识符中转义的相同规则也适用于字符串字面量。有关更多详细信息,请参阅 字符串

字面量

在 ClickHouse 中,字面量是直接在查询中表示的值。换句话说,它是在查询执行期间不会更改的固定值。

字面量可以是

我们将在下面的章节中更详细地了解其中的每一个。

字符串

字符串字面量必须用单引号括起来。不支持双引号。

转义可以通过以下两种方式实现

  • 使用前导单引号,其中单引号字符 '(且仅此字符)可以转义为 '',或者
  • 使用前导反斜杠以及下表中列出的以下支持的转义序列。
注意

反斜杠会失去其特殊含义,即如果它位于以下列出的字符之外的其他字符之前,则按字面意思解释。

支持的转义描述
\xHH8 位字符规范,后跟任意数量的十六进制数字 (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 解析为 UInt161, 10_000_000, 18446744073709551615, 01
有关更多信息,请参阅 数据类型0.1
数值字面量中的下划线 _ 会被忽略,并且可以用于提高可读性。支持以下数值字面量
数值字面量示例
整数十进制数
指数表示法1e100-1e-100
浮点数123.456infnan
十六进制0xc0fe
注意

SQL 标准兼容的十六进制字符串

x'c0fe'

二进制

注意

0b1101

SQL 标准兼容的二进制字符串

b'1101'

注意

不支持八进制字面量,以避免解释中发生意外错误。

  • 复合
  • 数组使用方括号 [1, 2, 3] 构建。元组使用圆括号 (1, 'Hello, world!', 2) 构建。从技术上讲,这些不是字面量,而是带有数组创建运算符和元组创建运算符的表达式。数组必须至少包含一项,而元组必须至少包含两项。
  • 当元组出现在 SELECT 查询的 IN 子句中时,存在一个特殊情况。查询结果可以包含元组,但元组无法保存到数据库(使用 Memory 引擎的表除外)。

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 NULLIS NOT NULL 运算符以及相关的函数 isNullisNotNull 来检查 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 定义了名为 abcd 的参数 - 每个参数都具有不同的数据类型

now()

使用 clickhouse-client 的示例

查询参数不是通用的文本替换,不能在任意 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 子句中的表名或列名定义别名,而无需使用 AS 关键字。SELECT table_name_alias.column_name FROM table_name table_name_aliasCAST 函数中,AS 关键字具有另一层含义。请参阅该函数的描述。.

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