为什么我的 PostgreSQL v13 被零除?我想应该过滤掉行

Why I get division by zero for PostgreSQL v13? I suppose rows should be filtered out

运行 不同版本的 PostgreSQL 上的相同查询给出不同的结果。

WITH t(a, b) AS (VALUES (1, 0))
SELECT a / b
  FROM t
 WHERE b <> 0;

v11.10 我没有得到预期的行 fiddle
v13.1 我得到 ERROR: division by zero fiddle

为什么我的 PostgreSQL v13.1 被零除?我想应该像 v11.10

那样过滤掉行

UPD
我认为当我们加入时,优化器有时不应该调用横向函数(可能的时候)并节省时间: fiddle

看起来求值的顺序不是人们所期望的那样:也就是说,人们会期望 0 分母会在计算之前被 where 子句过滤掉select 子句发生了。显然数据库选择以不同的方式做事。

但是,您可以使用 nullif():

轻松解决此问题
with t(a, b) as (values (1, 0))
select a / nullif(b, 0)
from t
where b <> 0;

这不会产生任何行。

我倾向于将其视为错误,或者至少是回归。在 db<>fiddle 中试玩,您的原始代码在版本 9.4、9.5、9.6、10 和 11 中运行良好,但在版本 12 和 13 中运行失败。

较新版本的 PostgreSQL(从 12 开始)通过您对常量单行 VALUES 列表的奇怪使用来查看常量折叠机会。但它会在折叠 WHERE 常量之前折叠除法常量,因此会遇到错误。

在 11 中,在其他类似的地方仍然会出现错误,例如:

select 1/0 from pgbench_accounts where aid < -100;

如果您试图想出一个非常简单的示例,它本身没有用,但只是为了测试其他东西,这可能会很烦人。但我只是把它归结为“玩愚蠢的游戏,赢得愚蠢的奖品”,然后找到其他方法来测试我想测试的东西。在您的情况下,您可以使 CTE 实现。

WITH t(a, b) AS materialized (VALUES (1, 0))
SELECT a / b            
  FROM t
 WHERE b <> 0;