如何在SQL(Postgres)中强制过滤评估顺序?

T.R*_*.R. 5 sql postgresql

我有一个表,简化,看起来大致像这样:

id | type | header    | body
===========================================
 1 | A    | {type: A} | {content: "Hi"}
 2 | A    | {type: A} | {content: "Hello"}
 3 | B    | {type: B} | ["Hi","Hello"]
Run Code Online (Sandbox Code Playgroud)

以下查询给出了一个错误:

> select * from Table where header->>'type'='A' and body->>'content' like 'H%'
ERROR:  cannot extract field from a non-object
Run Code Online (Sandbox Code Playgroud)

这是公平的,但这个查询也是如此:

> select * from (select * from Table where header->>'type'='A') where body->>'content' like 'H%'
Run Code Online (Sandbox Code Playgroud)

而这些不是:

> select * from Table where type='A' and body->>'content' like 'H%'
> select * from Table where header->>'type'='A' and body->>'content'='Hello'
Run Code Online (Sandbox Code Playgroud)

我有针对这个特定情况的解决方法(其中'喜欢'谓词不正确地给予优先权),但我担心的是我显然甚至不能依靠括号来控制评估顺序,即使在这种情况下,例如,它改变了适用于数据的约束条件.有没有一般的方法来做到这一点?

Gor*_*off 5

您应该能够通过以下方式强制执行评估顺序case

select *
from Table
where (case when header->>'type'='A'
            then (case when body->>'content' like 'H%' then 1 end)
       end) = 1;
Run Code Online (Sandbox Code Playgroud)

这大约是我唯一一次建议case在条款中添加陈述where

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

with t as (
      select t.*
      from table t
      where header->>'type'='A'
     )
select t.*
from t
where body->>'content' like 'H%';
Run Code Online (Sandbox Code Playgroud)

然而,这会带来实现中间结果的额外开销。