ByteHouse 的 SQL 语法即为 ClickHouse SQL。ClickHouse SQL 和 ANSI SQL (标准 SQL)的语法基本一致,绝大多数语法没有差异。关于不兼容 ANSI SQL 的部分,请官网文档参考:ClickHouse SQL语法与ANSI SQL的差异。
ClickHouse 支持的语法类型包括:
我们在本文档中仅列出常用的 SELECT
,CREATE
,ALTER
,INSERT INTO
,DROP
。其余语法可参考 社区文档。
由于 ByteHouse 的分布式设计理念与一般数据库不同。在了解语法前,请先学习 架构概述,并了解以下两个概念:
Distributed
(引擎详情)
*MergeTree
的表(常用的包含 HaMergeTree,HaUniqueMergeTree)。本地表的命名通常为 分布式表名_local
。
on cluster
语法为了充分利用每个节点的计算和存储能力,需要您将 DDL/DML 语句发送到每个节点上。系统提供了一种非常方便的语法,即 on cluster <cluster_name>
,将其加在 DDL/DML 语句上,即可实现将语句发送到每个节点,完成各节点上的库表元数据同步。
SELECT
SELECT
语法用于执行数据检索。 默认情况下,将请求的数据返回给客户端。
注意
一般情况下,Select 语句中的表请指定 Distributed 表,可以查询到全部节点的数据。如果查 Local 表,则只能查到某一节点的数据。
[WITH expr_list|(subquery)] SELECT [DISTINCT] expr_list [FROM [db.]table | (subquery) | table_function] [FINAL] [SAMPLE sample_coeff] [ARRAY JOIN ...] [GLOBAL] [ANY|ALL|ASOF] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI] JOIN (subquery)|table (ON <expr_list>)|(USING <column_list>) [PREWHERE expr] [WHERE expr] [GROUP BY expr_list] [WITH TOTALS] [HAVING expr] [ORDER BY expr_list] [WITH FILL] [FROM expr] [TO expr] [STEP expr] [LIMIT [offset_value, ]n BY columns] [LIMIT [n, ]m] [WITH TIES] [UNION ALL ...] [INTO OUTFILE filename] [FORMAT format]
每个可选子句的具体内容与使用技巧在 ClickHouse 社区文档中介绍,请参阅对应部分:
摘自 ClickHouse 官网。查询数据集为 New Your Taxi 数据集示例。
SQL 示例如下:
--统计不同出租车类型的打车次数 SELECT cab_type, count(*) FROM trips_mergetree GROUP BY cab_type; --统计不同乘客数量的平均金额 SELECT passenger_count, avg(total_amount) FROM trips_mergetree GROUP BY passenger_count; --统计每年不同乘客数量的总打车次数 SELECT passenger_count, toYear(pickup_date) AS year, count(*) FROM trips_mergetree GROUP BY passenger_count, year; --统计每年不同乘客数量不同打车距离的总打车次数,按年份与打车次数倒序排列 SELECT passenger_count, toYear(pickup_date) AS year, round(trip_distance) AS distance, count(*) FROM trips_mergetree GROUP BY passenger_count, year, distance ORDER BY year, count(*) DESC;
INSERT INTO 语句主要用于向系统中添加数据。SELECT
语法用于执行数据检索。 默认情况下,将请求的数据返回给客户端。
基本语法格式:
INSERT INTO [db.]table [(c1, c2, c3)] VALUES (v11, v12, v13), (v21, v22, v23), ...
对于存在于表结构中但不存在于插入列表中的列,它们将会按照如下方式填充数据:
DEFAULT
表达式,根据DEFAULT
表达式计算被填充的值。DEFAULT
表达式,则填充零或空字符注意
一般情况下,建议 Insert Into 指定分布式表。插入本地表虽然也能有效将数据插入集群中,但由于跳过了分布式表的分片逻辑,易造成数据不均衡。
SELECT
的结果写入INSERT INTO [db.]table [(c1, c2, c3)] SELECT ...
写入目标表的列与 SELECT
的列是一一对应的,尽管它们在 SELECT 表达式与目标表中的名称可能是不同的。
如果需要,会对插入数据执行对应的类型转换。
INSERT INTO [db.]table [(c1, c2, c3)] FROM INFILE file_name [COMPRESSION type] FORMAT format_name
使用上面的语句可以从客户端的文件上读取数据并插入表中。
COMPRESSION
语句中指明,支持的文件压缩格式如下:'none'
, 'gzip'
, 'deflate'
, 'br'
, 'xz'
, 'zstd'
, 'lz4'
, 'bz2'
。这个功能在 command-line client 和 clickhouse-local 是可用的。可以用于插入本地的数据。样例如下:
echo 1,A > input.csv ; echo 2,B >> input.csv clickhouse-client --query="CREATE TABLE table_from_file (id UInt32, text String) ENGINE=MergeTree() ORDER BY id;" clickhouse-client --query="INSERT INTO table_from_file FROM INFILE 'input.csv' FORMAT CSV;" clickhouse-client --query="SELECT * FROM table_from_file FORMAT PrettyCompact;"
结果:
┌─id─┬─text─┐ │ 1 │ A │ │ 2 │ B │ └────┴──────┘
这种语法比较适合小文件(≤200MB)的导入,优势是操作简单。但如果需要实现大文件的高效导入,请参考 批式导入。
该语句用于根据指定名称创建 Atomic 引擎(默认引擎)的数据库。
CREATE DATABASE [IF NOT EXISTS] db_name ON CLUSTER cluster_name
如果语句中存在IF NOT EXISTS
,则当数据库已经存在时,该语句不会返回任何错误。
若创建 MaterializeMySQL 引擎,请参考 通过MaterializedMySQL导入。
对于CREATE TABLE
,默认的语法为:
CREATE TABLE [IF NOT EXISTS] [db.]table_name ON CLUSTER cluster_name ( name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1], name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2], ... ) ENGINE = engine
具体引擎的语法差异,请参考:HaMergeTree,HaUniqueMergeTree,Distributed。
注意
CREATE TABLE [IF NOT EXISTS] [db.]table_name AS [db2.]name2 On Cluster cluster_name [ENGINE = engine]
创建一个与db2.name2
具有相同结构的表,如不填 Engine,则复制的表默认和原表使用相同的表引擎。
CREATE TABLE [IF NOT EXISTS] [db.]table_name On Cluster cluster_name ENGINE = engine AS SELECT ...
使用指定的引擎创建一个与SELECT
子句的结果具有相同结构的表,并使用SELECT
子句的结果填充它。这个语法仅适合本地表,请注意 SELECT
子句中指定本地表。
ALTER
操作有多种形式。以下仅列出对表结构的修改操作。语法示例如下:
ALTER TABLE [db].name ON CLUSTER cluster_name ADD|DROP|RENAME|CLEAR|COMMENT|{MODIFY|ALTER}|MATERIALIZE COLUMN ...
ALTER TABLE [db].name ON CLUSTER cluster_name ADD COLUMN [IF NOT EXISTS] name [type] [default_expr] [codec] [AFTER name_after]
使用指定的name
, type
, codec 以及 default_expr,往表中增加新的列。
添加列仅仅是改变原有表的结构。不会对已有数据产生影响。执行完 ALTER
后磁盘中也不会出现新的数据,当数据块完成合并后,磁盘中才会出现该列的数据。
ALTER TABLE [db].name ON CLUSTER cluster_name DROP COLUMN [IF EXISTS] name
通过指定 name
删除列。从文件系统中删除数据。由于是删除列的整个文件,该语句几乎是立即执行完成的。
ALTER TABLE visits DROP COLUMN browser
警告
删除列是高危操作,删除数据后可能无法操作,请谨慎执行。
ALTER TABLE [db].name ON CLUSTER cluster_name MODIFY COLUMN [IF EXISTS] name [type] [default_expr] [TTL]
该语句可以改变 name
列的属性:
如果只改变了默认表达式,该语句几乎不会做任何复杂操作,几乎是立即执行完成的。
但当改变列的类型时,列的值也被转换了,如同对列使用 toType 函数一样。改变列的类型是唯一的复杂型动作 - 它改变了数据文件的内容。对于大型表,执行起来要花费较长的时间。因此,该操作不建议在生产环境下进行。
ALTER
操作会阻塞对表的所有读写操作。换句话说,当一个大的 SELECT
语句和 ALTER
同时执行时,ALTER
会等待,直到 SELECT
执行结束。与此同时,当 ALTER
运行时,新的 SQL 语句将会等待。Distributed
表), ALTER
仅仅改变了自身的表结构,不会改变从属的表结构。删除现有实体。 如果指定了IF EXISTS
子句,如果实体不存在,这些查询不会返回错误。
删除db
数据库中的所有表,然后删除db
数据库本身。
DROP DATABASE [IF EXISTS] db ON CLUSTER cluster_name
删除数据表。
DROP [TEMPORARY] TABLE [IF EXISTS] [db.]name ON CLUSTER cluster
警告
删除库表是高危操作,操作后数据可能无法恢复。