Возникли некоторые проблемы при попытке отфильтровать результаты, возвращаемые из PostgreSQL, на основе определенных идентификаторов

#sql #postgresql

#sql #postgresql

Вопрос:

Из-за скуки я решил настроить простую систему тегов для своих фильмов сегодня. У меня в основном есть список названий фильмов и X количество тегов для каждого фильма. База данных выглядит следующим образом:

 mydb=# select id, title from movies;

 id |                  title                   
---- ----------------------------------------
  1 | first_movie
  2 | second_movie

mydb=# select id, movie_id, tag_id from movie_tags;

 id | movie_id | tag_id 
---- ---------- --------
  1 |        1 |    716
  2 |        1 |    787
  3 |        1 |    322
  4 |        2 |    716
  5 |        2 |    787
  6 |        2 |    323

mydb=# SELECT l.id, l.title, t.tag_id FROM movies l, movie_tags t WHERE t.movie_id = l.id AND t.tag_id IN(716, 787, 323);

 id |    title     | tag_id 
---- -------------- --------
  2 | second_movie |    787
  2 | second_movie |    716
  2 | second_movie |    323
  1 | first_movie  |    716
  1 | first_movie  |    787
  

Это третий запрос, который вызывает у меня проблемы. Во-первых, он показывает повторяющиеся строки. Новая строка для каждого tag_id . Я этого не хочу. Я бы предпочел, чтобы для каждого фильма отображалась одна строка, соответствующая указанным тегам.

Что приводит меня ко второй проблеме. Как вы можете видеть, first_movie не помечен tag_id=323 . Однако это все еще отображается в результатах.

Как я могу не показывать повторяющиеся строки и отфильтровать результаты по фильмам, которые соответствуют всем заданным тегам?

Я планировал создать для этого простой пользовательский интерфейс, поэтому надеялся на хороший «динамический» запрос, в который я могу поместить список tag_ids.

Ответ №1:

Этот запрос выдает вам все фильмы, в которых были найдены все 3 тега.

   SELECT l.id, l.title
    FROM movies l, movie_tags t
   WHERE t.movie_id = l.id
     AND t.tag_id IN (716, 787, 323)
GROUP BY l.id, l.title
  HAVING COUNT(*) = 3
  

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

Ответ №2:

 SELECT l.id, l.title
FROM movies l
WHERE l.id IN (SELECT t.movie_id 
               FROM movie_tags t 
               WHERE t.tag_id IN (716, 787, 323));