为什么 postgresql case 子句中两个逻辑上相同的条件有不同的行为?

问题描述

我有两个查询是 postgresql

1. SELECT CASE WHEN (1=1) THEN NULL ELSE cast(1/0 as text) END;
2. SELECT CASE WHEN (EXISTS (SELECT 10)) THEN NULL ELSE cast(1/0 as text) END;

您可能已经注意到两个查询中第一个条件的结果为真,但第一个查询的结果是 null,第二个查询的结果是 ERROR: division by zero

这里发生了什么?

在评估发生的顺序上是否有任何优化?如果是,是否有任何原因将其关闭

当条件结果为真时,是否有任何原因在条件块中有一个复杂的查询,而不会在 else 块中触发运行时错误

Postgresql 版本:13.1

解决方法

错误发生在计划查询时,而不是运行时。

在第一种情况下,在计划时已知 1=1 为真,导致整个 CASE 折叠为 NULL::text。因此,1=1CASE WHEN true 的常量折叠使您免于 1/0 的常量折叠异常。您可以通过执行 EXPLAIN VERBOSE 来看到这一点。

当条件结果为真时,是否有任何原因在条件块中有一个复杂的查询,而不会在 else 块中触发运行时错误?

是的,除非它不是真正在运行时出现问题。

就像一个虚拟的 SELECT 打败了防止问题的常量折叠,另一个虚拟的 select 可以打败导致问题的常量折叠。

SELECT CASE WHEN (EXISTS (SELECT 10)) THEN NULL::text ELSE cast (1/(select 0) as text)  END;