简体   繁体   English

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

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

Running same query on different versions of PostgreSQL gives different result.在不同版本的 PostgreSQL 上运行相同的查询会得到不同的结果。

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

On v11.10 I get no rows as expected fiddlev11.10 ,我没有像预期的那样得到任何行
On v13.1 I get ERROR: division by zero fiddlev13.1我得到ERROR: division by zero 小提琴

Why I get division by zero for PostgreSQL v13.1 ?为什么 PostgreSQL v13.1被零除? I suppose rows should be filtered out as it done for v11.10我想应该像v11.10那样过滤掉行

UPD UPD
I think when we join, optimizer should not call lateral function sometimes (when it may) and save time: fiddle我认为当我们加入时,优化器有时(可能时)不应该调用横向 function 并节省时间: 小提琴

Newer versions of PostgreSQL (starting in 12) look through your strange use of the constant single row VALUES list to see the constant-folding opportunity.较新版本的 PostgreSQL(从 12 开始)查看您对常量单行VALUES 列表的奇怪使用,以查看常量折叠机会。 But it folds the division constant before it folds the WHERE constant, and so trips over the error.但是它在折叠 WHERE 常量之前折叠除法常数,因此会出现错误。

In 11, you would still get the error in other similar places, like:在 11 中,您仍然会在其他类似的地方遇到错误,例如:

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

This can be annoying if you are trying to come up with a very simple example not useful in its own right, but just to test something else.如果您试图提出一个非常简单的示例,这可能会很烦人,它本身并没有用,而只是为了测试其他东西。 But I just chalk it up to "Play stupid games, win stupid prizes", and find some other way to test what I want to test.但我只是把它归结为“玩愚蠢的游戏,赢得愚蠢的奖品”,并找到其他方法来测试我想要测试的内容。 In your case, you can just make the CTE be materialized.在您的情况下,您可以使 CTE 物化。

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

It looks the order of evaluation is not what one would expect it to be: that is, one would expect that 0 denominators would be filtered out by the where clause before the computation in the select clause happens.看起来评估的顺序并不是人们期望的那样:也就是说,人们期望在select子句中的计算发生之前, 0分母会被where子句过滤掉。 Obviously the database chooses to do things differently.显然,数据库选择以不同的方式做事。

You can, however, easily work around this with nullif() :但是,您可以使用nullif()轻松解决此问题:

with t(a, b) as (values (1, 0))
select a / nullif(b, 0)
from t
where b <> 0;

This properly produce no rows.这正确地不产生任何行。

I would tend qualifying this as a bug, or at least a regression.我倾向于将此定义为错误,或者至少是回归。 Playing around in db<>fiddle , your original code works fine in versions 9.4, 9.5, 9.6, 10 and 11, but fails in versions 12 and 13.db<>fiddle中玩耍,您的原始代码在版本 9.4、9.5、9.6、10 和 11 中运行良好,但在版本 12 和 13 中失败。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM