【问题标题】:Why two logically same conditions in postgresql case clause have different behavior?为什么 postgresql case 子句中两个逻辑上相同的条件有不同的行为?
【发布时间】:2021-10-03 16:06:56
【问题描述】:

我有两个查询是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;

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

这里发生了什么?

评估发生的顺序是否有任何优化?如果是,有什么理由要关闭它?

为什么条件块中有一个复杂的查询,当条件结果为真时不会在 else 块中触发运行时错误?

Postgresql 版本:13.1

【问题讨论】:

  • 3. SELECT CASE WHEN (SELECT 1=1) THEN NULL ELSE cast(1/0 as text) END; 检查是否是短路失败的子查询。
  • 参见此处CASE:“如第 4.2.14 节所述,在不同时间计算表达式的子表达式的情况有很多种,因此“CASE 仅计算必要的子表达式”的原则”不是铁定的。例如,一个恒定的 1/0 子表达式通常会导致在计划时被零除失败,即使它在一个永远不会在运行时输入的 CASE 臂内”。部分4.2.14

标签: sql postgresql lazy-evaluation order-of-execution


【解决方案1】:

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

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

为什么条件块中有一个复杂的查询,当条件结果为真时不会在 else 块中触发运行时错误?

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

就像一个虚拟 SELECT 击败了阻止问题的常量折叠一样,另一个虚拟选择可以击败导致问题的常量折叠。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    • 1970-01-01
    • 2022-11-27
    • 2016-05-11
    • 1970-01-01
    • 1970-01-01
    • 2019-09-08
    相关资源
    最近更新 更多