Объедините CTE вместе с IN в PostgreSQL - PullRequest
0 голосов
/ 07 сентября 2018

Итак, у меня есть этот простой запрос в 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) ;

Я получаю ошибку column "bunch_of_things" does not exist

Я знаю, что мог бы поместить первый выбор в скобки второго запроса, чтобы определить часть IN

Но так как я буду использовать результаты первого запроса несколько раз в одной транзакции, я не хочу делать один и тот же запрос несколько раз.

Так как я могу заставить IN работать вместе с CTE?

(И если это невозможно, как я могу получить результаты запроса один раз и использовать их несколько раз в транзакции?)

Спасибо

Ответы [ 2 ]

0 голосов
/ 08 сентября 2018

Это всегда будет медленно, потому что в PostgreSQL CTE - это забор оптимизации.

Тебе захочется что-то подобное,

SELECT *
FROM vans
WHERE EXISTS (
    SELECT
    FROM shoes
    WHERE adidas_id = 1
      AND vans_id = vans.id
)

это будет намного быстрее.

0 голосов
/ 07 сентября 2018

Имя 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);

Есть несколько вещей, которые необходимо учитывать.

Во-первых, 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
)

Во-вторых, в 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;

А затем используйте таблицу как обычно:

select * 
  from vans v
where EXISTS (
    select 1
    from bunch_of_things b
    where b.vans_id = v.id
)
...