如何在SQL(Postgres)中强制筛选求值顺序?

如何在SQL(Postgres)中强制筛选求值顺序?,sql,postgresql,Sql,Postgresql,我有一张表,简化后大致如下: id | type | header | body =========================================== 1 | A | {type: A} | {content: "Hi"} 2 | A | {type: A} | {content: "Hello"} 3 | B | {type: B} | ["Hi","Hello"] 以下查询提供了一个错误: > select * from Table w

我有一张表,简化后大致如下:

id | type | header    | body
===========================================
 1 | A    | {type: A} | {content: "Hi"}
 2 | A    | {type: A} | {content: "Hello"}
 3 | B    | {type: B} | ["Hi","Hello"]
以下查询提供了一个错误:

> select * from Table where header->>'type'='A' and body->>'content' like 'H%'
ERROR:  cannot extract field from a non-object
这很公平,但这个问题也是如此:

> select * from (select * from Table where header->>'type'='A') where body->>'content' like 'H%'
鉴于这些不包括:

> select * from Table where type='A' and body->>'content' like 'H%'
> select * from Table where header->>'type'='A' and body->>'content'='Hello'

对于这种特定的情况(like谓词被错误地赋予了优先权),我有解决办法,但我担心的是,我甚至不能依靠括号来控制计算顺序,即使在这种情况下,它改变了应用于数据的约束。有什么常规方法可以做到这一点吗?

您应该能够使用
案例
强制执行评估顺序:

select *
from Table
where (case when header->>'type'='A'
            then (case when body->>'content' like 'H%' then 1 end)
       end) = 1;
这大概是我唯一一次建议将
case
语句放在
where
子句中

您还可以使用CTE保证订单:

with t as (
      select t.*
      from table t
      where header->>'type'='A'
     )
select t.*
from t
where body->>'content' like 'H%';
但是,这会带来实现中间结果的额外开销。

(这是补充信息;Gordon的答案应该标记为正确)

在SQL中,DB可以任意顺序执行谓词。没有短路。括号内的组覆盖默认运算符优先级,以控制哪些运算符绑定到哪些操作数,但不强制执行顺序

子查询不能保证执行顺序。在可能的情况下,可以并且应该通过将其展平到外部查询来优化它

您遇到的问题与处理被零除的问题相同,并且具有相同的解决方案


正确的解决方案是使用
CASE
强制执行顺序,如Gordon所示。您可以使用CTE(
)或
偏移量0
破解,但两者都会影响性能。

太棒了,谢谢。我没有意识到CTE的计算与嵌套查询不同——我认为它们主要是为了避免名称空间污染。很高兴知道。