DuckDB 的 SQL 方言严格遵循 PostgreSQL 方言的惯例。本页列出了少数几个例外情况。
浮点运算
DuckDB 和 PostgreSQL 在处理除以零时的浮点运算方式不同。DuckDB 在处理除以零和涉及无穷大值的运算时均符合 IEEE 浮点运算标准 (IEEE 754)。PostgreSQL 在除以零时会报错,但在处理无穷大值时与 IEEE 754 标准一致。要查看这些差异,请运行以下 SQL 查询:
SELECT 1.0 / 0.0 AS x;
SELECT 0.0 / 0.0 AS x;
SELECT -1.0 / 0.0 AS x;
SELECT 'Infinity'::FLOAT / 'Infinity'::FLOAT AS x;
SELECT 1.0 / 'Infinity'::FLOAT AS x;
SELECT 'Infinity'::FLOAT - 'Infinity'::FLOAT AS x;
SELECT 'Infinity'::FLOAT - 1.0 AS x;
| 表达式 | PostgreSQL | DuckDB | IEEE 754 |
|---|---|---|---|
| 1.0 / 0.0 | 错误 | 无穷大 (Infinity) | 无穷大 (Infinity) |
| 0.0 / 0.0 | 错误 | 非数字 (NaN) | 非数字 (NaN) |
| -1.0 / 0.0 | 错误 | 负无穷大 (-Infinity) | 负无穷大 (-Infinity) |
| 'Infinity' / 'Infinity' | 非数字 (NaN) | 非数字 (NaN) | 非数字 (NaN) |
| 1.0 / 'Infinity' | 0.0 | 0.0 | 0.0 |
| 'Infinity' - 'Infinity' | 非数字 (NaN) | 非数字 (NaN) | 非数字 (NaN) |
| 'Infinity' - 1.0 | 无穷大 (Infinity) | 无穷大 (Infinity) | 无穷大 (Infinity) |
整数除法
在执行整数除法运算时,PostgreSQL 执行整数除法,而 DuckDB 执行浮点除法。
SELECT 1 / 2 AS x;
PostgreSQL 返回 0,而 DuckDB 返回 0.5。
要在 DuckDB 中执行整数除法,请使用 // 运算符。
SELECT 1 // 2 AS x;
这将返回 0。
布尔值和整数值的 UNION 操作
以下查询在 PostgreSQL 中会失败,但在 DuckDB 中可以成功完成。
SELECT true AS x
UNION
SELECT 2;
PostgreSQL 返回错误
ERROR: UNION types boolean and integer cannot be matched
DuckDB 执行强制类型转换,因此它能完成查询并返回以下结果
| x |
|---|
| 1 |
| 2 |
相等性检查中的隐式转换
DuckDB 在相等性检查中执行隐式类型转换,例如将字符串转换为数值或布尔值。因此,在某些情况下,PostgreSQL 会抛出错误,而 DuckDB 可以成功计算出结果:
| 表达式 | PostgreSQL | DuckDB |
|---|---|---|
| '1.1' = 1 | 错误 | true |
| '1.1' = 1.1 | true | true |
| 1 = 1.1 | false | false |
| true = 'true' | true | true |
| true = 1 | 错误 | true |
| 'true' = 1 | 错误 | 错误 |
引号标识符的大小写敏感性
PostgreSQL 是大小写不敏感的。PostgreSQL 实现不敏感性的方式是将 SQL 中未加引号的标识符转换为小写,而使用引号则保留大小写。例如,以下命令会创建一个名为 mytable 的表,但在查询时尝试查找 MyTaBLe,因为引号保留了大小写。
CREATE TABLE MyTaBLe (x INTEGER);
SELECT * FROM "MyTaBLe";
ERROR: relation "MyTaBLe" does not exist
PostgreSQL 不仅将引号标识符视为大小写敏感,它将所有标识符都视为大小写敏感。例如,以下操作也无法工作:
CREATE TABLE "PreservedCase" (x INTEGER);
SELECT * FROM PreservedCase;
ERROR: relation "preservedcase" does not exist
因此,PostgreSQL 中的大小写不敏感仅在你不使用不同大小写的引号标识符时才有效。
对于 DuckDB,这种行为在与默认大小写敏感的其他工具(如 Parquet, Pandas)进行交互时会产生问题——因为所有标识符都会被强制转换为小写。因此,DuckDB 通过使系统内部的标识符保持完全大小写不敏感,同时 保留其原始大小写 来实现大小写不敏感。
在 DuckDB 中,上述脚本可以成功执行:
CREATE TABLE MyTaBLe (x INTEGER);
SELECT * FROM "MyTaBLe";
CREATE TABLE "PreservedCase" (x INTEGER);
SELECT * FROM PreservedCase;
SELECT tbl FROM duckdb_tables();
| tbl |
|---|
| MyTaBLe |
| PreservedCase |
PostgreSQL 将标识符转换为小写的行为可以通过 preserve_identifier_case 选项 来实现。
SET preserve_identifier_case = false;
CREATE TABLE MyTaBLe (x INTEGER);
SELECT tbl FROM duckdb_tables();
| tbl |
|---|
| mytable |
但是,系统中针对标识符的大小写不敏感匹配无法关闭。
使用双等号进行比较
DuckDB 同时支持 = 和 == 进行相等性比较,而 PostgreSQL 仅支持 =。
SELECT 1 == 1 AS t;
DuckDB 返回 true,而 PostgreSQL 返回:
postgres=# SELECT 1 == 1 AS t;
ERROR: operator does not exist: integer == integer
LINE 1: SELECT 1 == 1 AS t;
请注意,由于可移植性有限,不建议使用 ==。
清理 (Vacuuming) 表
在 PostgreSQL 中,VACUUM 语句用于垃圾回收和分析表。在 DuckDB 中,VACUUM 语句仅用于重建统计信息。有关回收空间的说明,请参阅“回收空间”页面。
字符串
从 1.3.0 版本开始,DuckDB 会对嵌套数据结构中序列化的字符串中的 ' 等字符进行转义。PostgreSQL 不会这样做。
例如,运行:
SELECT ARRAY[''''];
PostgreSQL 返回:
{'}
DuckDB 返回:
['\'']
函数
regexp_extract 函数
与 PostgreSQL 的 regexp_substr 函数不同,当没有匹配项时,DuckDB 的 regexp_extract 返回空字符串,而不是 NULL。
to_date 函数
DuckDB 不支持 to_date PostgreSQL 日期格式化函数。请改用 strptime 函数。
date_part 函数
由 date_part 函数提取的大多数部分都作为整数返回。由于 DuckDB 中没有无穷大的整数值,因此对于无穷大的时间戳,会返回 NULL。
Schema 中类型名称的解析
对于 CREATE TABLE 语句,DuckDB 尝试在创建表的 Schema 中解析类型名称。例如:
CREATE SCHEMA myschema;
CREATE TYPE myschema.mytype AS ENUM ('as', 'df');
CREATE TABLE myschema.mytable (v mytype);
PostgreSQL 在最后一条语句上返回错误。
ERROR: type "mytype" does not exist
LINE 1: CREATE TABLE myschema.mytable (v mytype);
DuckDB 执行该语句并成功创建表,通过以下查询确认:
DESCRIBE myschema.mytable;
| 列名 (column_name) | 列类型 (column_type) | null | key | 默认值 (default) | 额外信息 (extra) |
|---|---|---|---|---|---|
| v | ENUM('as', 'df') | 是 (YES) | NULL | NULL | NULL |
利用函数依赖进行 GROUP BY
PostgreSQL 可以利用函数依赖,例如在以下查询中的 i -> j:
CREATE TABLE tbl (i INTEGER, j INTEGER, PRIMARY KEY (i));
SELECT j
FROM tbl
GROUP BY i;
PostgreSQL 运行该查询。
DuckDB 失败。
Binder Error:
column "j" must appear in the GROUP BY clause or must be part of an aggregate function.
Either add it to the GROUP BY list, or use "ANY_VALUE(j)" if the exact value of "j" is not important.
要解决此问题,请添加其他属性或使用 GROUP BY ALL 子句。
正则表达式匹配运算符的行为
PostgreSQL 支持 POSIX 正则表达式匹配运算符 ~(大小写敏感的部分正则匹配)和 ~*(大小写不敏感的部分正则匹配),以及它们的否定变体 !~ 和 !~*。
在 DuckDB 中,~ 等同于 regexp_full_match,!~ 等同于 NOT regexp_full_match。运算符 ~* 和 !~* 不受支持。
下表显示了 PostgreSQL 和 DuckDB 中这些函数之间的对应关系几乎不存在。请避免在 DuckDB 中使用 POSIX 正则表达式匹配运算符。
| 表达式 | PostgreSQL | DuckDB |
|---|---|---|
'aaa' ~ '(a|b)' |
true | false |
'AAA' ~* '(a|b)' |
true | 错误 |
'aaa' !~ '(a|b)' |
false | true |
'AAA' !~* '(a|b)' |
false | 错误 |