在 PostgreSQL 中将 CTE 与 IN 结合起来

sle*_*vin 6 postgresql transactions common-table-expression sql-in postgresql-10

所以我在 PostgreSQL 10 中有这个简单的查询。

with bunch_of_things as (
    select vans_id from shoes where adidas_id = 1
)

select * from vans where vans.id in (bunch_of_things) ;
Run Code Online (Sandbox Code Playgroud)

我收到错误column "bunch_of_things" does not exist

我知道我可以将第一个选择放在第二个查询的括号内,以定义 IN 部分

但由于我将在同一事务中多次使用第一个查询的结果,因此我不想多次执行相同的查询。

那么如何才能让 IN 与 CTE 一起工作呢?

(如果这是不可能的,我怎样才能获得一次查询结果并在事务中多次使用它们?)

谢谢

Rom*_*val 5

CTE 的名称就像一个表,因此您应该进行选择

with bunch_of_things as (
    select vans_id from shoes where adidas_id = 1
)

select * from vans where vans.id in (select vans_id from bunch_of_things);
Run Code Online (Sandbox Code Playgroud)

但您需要考虑几件事。

首先,EXISTS通常比IN

with bunch_of_things as (
    select vans_id from shoes where adidas_id = 1
) 
select * 
  from vans v
where EXISTS (
    select 1
    from bunch_of_things b
    where b.vans_id = v.id
)
Run Code Online (Sandbox Code Playgroud)

其次,在 postgres 10 及以下版本中,CTE 是一个性能围栏,因此 postgres 无法整体优化查询(但这可能会改变)。在某些情况下,这可能是控制查询执行的有用方法,并且绝对是您应该考虑的事情。

执行查询并在事务中重用结果的另一种方法是使用临时表,如下所示:

CREATE TEMPORARY TABLE bunch_of_things (vans_id integer)
ON COMMIT DROP;

INSERT INTO bunch_of_things (vans_id)
SELECT vans_id FROM shoes where adidas_id = 1;
Run Code Online (Sandbox Code Playgroud)

然后照常使用该表:

select * 
  from vans v
where EXISTS (
    select 1
    from bunch_of_things b
    where b.vans_id = v.id
)
Run Code Online (Sandbox Code Playgroud)