DuckDB 提供了几种高级 SQL 功能和语法糖,以使 SQL 查询更加简洁。我们通常将这些称为“友好的 SQL”。
这些特性中的一些在其他系统中也得到支持,而有些(目前)是DuckDB独有的。
Clauses
- 创建表和插入数据:
CREATE OR REPLACE TABLE
: 避免在脚本中使用DROP TABLE IF EXISTS
语句。CREATE TABLE ... AS SELECT
(CTAS): 从表的输出中创建一个新表,而无需手动定义模式。INSERT INTO ... BY NAME
: 这种INSERT
语句的变体允许使用列名而不是位置。INSERT OR IGNORE INTO ...
: 插入不会因UNIQUE
或PRIMARY KEY
约束而导致冲突的行。INSERT OR REPLACE INTO ...
: 插入不会因UNIQUE
或PRIMARY KEY
约束而导致冲突的行。对于导致冲突的行,将现有行的列替换为要插入行的新值。
- 描述表和计算统计信息:
- 使SQL子句更紧凑:
FROM
-first syntax with an optionalSELECT
clause: DuckDB允许以FROM tbl
形式进行查询,选择所有列(执行SELECT *
语句)。GROUP BY ALL
: 通过从SELECT
子句中的属性列表推断分组列,省略分组列。ORDER BY ALL
: 对所有列进行排序的简写(例如,确保确定性结果)。SELECT * EXCLUDE
:EXCLUDE
选项允许从*
表达式中排除特定列。SELECT * REPLACE
:REPLACE
选项允许在*
表达式中用不同的表达式替换特定列。UNION BY NAME
: 根据列名执行UNION
操作(而不是依赖位置)。
- 转换表格:
- 定义SQL级别的变量:
查询功能
- 在
WHERE
、GROUP BY
和HAVING
中的列别名。(请注意,列别名不能在JOIN
子句的ON
子句中使用。) COLUMNS()
表达式 可以用于在多个列上执行相同的表达式:- 可重复使用的列别名,例如:
SELECT i + 1 AS j, j + 2 AS k FROM range(0, 3) t(i)
- 用于分析(OLAP)查询的高级聚合功能:
count()
简写 用于count(*)
字面量和标识符
Data Types
Data Import
- 自动检测CSV文件的标题和模式
- 直接查询 CSV 文件 和 Parquet 文件
- 使用语法
FROM 'my.csv'
,FROM 'my.csv.gz'
,FROM 'my.parquet'
等从文件加载。 - 文件名扩展(globbing), 例如:
FROM 'my-data/part-*.parquet'
函数和表达式
- 用于函数链的点操作符:
SELECT ('hello').upper()
- 字符串格式化器:
format()
函数与fmt
语法 和printf() 函数
- 列表推导式
- 列表切片
- 字符串切片
STRUCT.*
表示法- 简单的
LIST
和STRUCT
创建
连接类型
尾随逗号
DuckDB 允许在列出实体(例如列名和表名)以及构建 LIST
项 时使用 尾随逗号。
例如,以下查询有效:
SELECT
42 AS x,
['a', 'b', 'c',] AS y,
'hello world' AS z,
;
"Top-N in Group" 查询
在SQL中,按某些标准计算“组中的前N行”是一个常见任务,不幸的是,这通常需要一个涉及窗口函数和/或子查询的复杂查询。
为了帮助实现这一点,DuckDB 提供了聚合函数 max(arg, n)
, min(arg, n)
, arg_max(arg, val, n)
, arg_min(arg, val, n)
, max_by(arg, val, n)
和 min_by(arg, val, n)
,以高效地返回基于特定列的升序或降序排列的组中的“前”n
行。
例如,我们使用以下表格:
SELECT * FROM t1;
┌─────────┬───────┐
│ grp │ val │
│ varchar │ int32 │
├─────────┼───────┤
│ a │ 2 │
│ a │ 1 │
│ b │ 5 │
│ b │ 4 │
│ a │ 3 │
│ b │ 6 │
└─────────┴───────┘
我们想要获取每个组grp
中前3个val
值的列表。传统的方法是在子查询中使用窗口函数:
SELECT array_agg(rs.val), rs.grp
FROM
(SELECT val, grp, row_number() OVER (PARTITION BY grp ORDER BY val DESC) AS rid
FROM t1 ORDER BY val DESC) AS rs
WHERE rid < 4
GROUP BY rs.grp;
┌───────────────────┬─────────┐
│ array_agg(rs.val) │ grp │
│ int32[] │ varchar │
├───────────────────┼─────────┤
│ [3, 2, 1] │ a │
│ [6, 5, 4] │ b │
└───────────────────┴─────────┘
但在DuckDB中,我们可以更简洁(且高效!)地完成这个操作:
SELECT max(val, 3) FROM t1 GROUP BY grp;
┌─────────────┐
│ max(val, 3) │
│ int32[] │
├─────────────┤
│ [3, 2, 1] │
│ [6, 5, 4] │
└─────────────┘