⌘+k ctrl+k
1.3 (稳定版)
搜索快捷键 cmd + k | ctrl + k
PostgreSQL 兼容性

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 错误 无穷大 无穷大
0.0 / 0.0 错误 非数字 (NaN) 非数字 (NaN)
-1.0 / 0.0 错误 -无穷大 -无穷大
'Infinity' / 'Infinity' 非数字 (NaN) 非数字 (NaN) 非数字 (NaN)
1.0 / 'Infinity' 0.0 0.0 0.0
'Infinity' - 'Infinity' 非数字 (NaN) 非数字 (NaN) 非数字 (NaN)
'Infinity' - 1.0 无穷大 无穷大 无穷大

整数除法

在进行整数除法运算时,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 table_name FROM duckdb_tables();
表名 (table_name)
MyTaBLe
PreservedCase

PostgreSQL 将标识符转换为小写的行为可以通过 preserve_identifier_case 选项来访问。

SET preserve_identifier_case = false;
CREATE TABLE MyTaBLe (x INTEGER);
SELECT table_name FROM duckdb_tables();
表名 (table_name)
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 Tables)

在 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 函数

模式中类型名称的解析

对于 CREATE TABLE 语句,DuckDB 尝试解析创建表时模式中的类型名称。例如:

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) 错误