Как выбрать все записи, на которые ссылается указанный набор других записей - PullRequest
0 голосов
/ 07 апреля 2020

У меня есть две таблицы с ассоциацией «многие ко многим». Я хотел бы иметь возможность запустить один параметризованный запрос, который возвращает все строки на одной стороне, на которые ссылается указанный набор (произвольного размера) записей в другой таблице.

Чтобы проиллюстрировать проблема, рассмотрим случай (сравнимый с моим) таблицы:

  1. Mov ie
  2. Актер
  3. Movie_Actor таблица ссылок

Довольно просто написать запрос, чтобы вернуть все фильмы, в которых участвует данный актер, или даже любое указанное c число актеров, сыгравших одну из главных ролей, например,

SELECT * FROM Movie
WHERE Movie.ID IN (
  SELECT Movie_Actor.Movie_ID FROM Movie_Actor
  WHERE Movie_Actor.Actor_ID = ?
  )

Затем вы можете использовать INTERSECT или несколько операторов в предложении WHERE для его дальнейшего сужения. Но все эти подходы, насколько я могу судить, основаны на предопределенном фиксированном количестве условий в запросе. Конечно, вы можете собрать такой запрос в коде, но это противоречит моей цели. Я просто хочу один запрос, в который я могу вставить параметры.

И если я сделаю WHERE Movie_Actor.Actor_ID IN ?, тогда, конечно, я просто получу список всех фильмов, в которых был задействован любой актер из списка.

Я не вижу, как можно запросить список всех фильмов, в которых был набор актеров, в которых этот набор больше 0, но в остальном его размер не ограничен.

Есть ли способ построить такой запрос, который бы принимал набор actor_id s в качестве параметров?

1 Ответ

1 голос
/ 07 апреля 2020

Один из вариантов - использовать несколько exists условий:

select m.*
from movie m
where 
    exists (select 1 from movie_actor mv where mv.movie_id = m.id and mv.actor_id = ?)
    and exists (select 1 from movie_actor mv where mv.movie_id = m.id and mv.actor_id = ?)
    and ...

Это должен быть достаточно эффективный подход.

С другой стороны, вы можете использовать агрегацию, которая короче писать, но может быть немного медленнее (в зависимости от вашего набора данных) и требует перечисления столбцов для сохранения в movie:

select m.id, m.name
from movie m
inner join movie_actor mv 
    on  mv.movie_id = m.id 
    and mv.actor_id in (?, ?)  -- either one actor or the other
group by m.id, m.name
having count(*) = 2            -- both matched
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...