首页 > 解决方案 > 如何在mysql中添加'AND'标签排除

问题描述

我需要创建电影标题的过滤浏览。用户可以搜索所有包含浪漫、戏剧类型/标签的电影,但它们不能包含喜剧。

CREATE TABLE `movies` (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(100) NOT NULL DEFAULT '',
 
  PRIMARY KEY(`id`)
);

CREATE TABLE `genres` (
  `id` int NOT NULL AUTO_INCREMENT,
  `gname` varchar(32) NOT NULL DEFAULT '',
  PRIMARY KEY(`id`)
);

CREATE TABLE `genres_in_movies` (
  `genre_id` int NOT NULL,
  `movie_id` int NOT NULL,
  FOREIGN KEY (`genre_id`) REFERENCES `genres`(`id`),
  FOREIGN KEY (`movie_id`) REFERENCES `movies`(`id`)
);

INSERT INTO genres(gname) VALUES('Comedy'),('Horror'),('Drama'),('Suspense'),('Romance'),('Documentary');

INSERT INTO movies(title) VALUES("Zoolander"),("Inception"),("Jurassic");

insert into genres_in_movies(genre_id,movie_id) values 
(1,1),(3,1),(5,1),
(2,2),(4,2),
(6,2),
(1,3),(2,3),(3,3);

我在下面的小提琴中所做的包含部分工作。

SELECT DISTINCT m.id, m.title, gim.genres
FROM movies m
INNER JOIN genres_in_movies ON movie_id = m.id
INNER JOIN (
  SELECT movie_id, group_concat(genres.gname) as genres
  FROM genres_in_movies
  INNER JOIN genres ON genre_id = genres.id
  GROUP by movie_id
) AS gim ON gim.movie_id = m.id
WHERE genres_in_movies.genre_id IN (5)
AND genres_in_movies.genre_id not in(1)

但是,包含通过使用 OR 起作用,如果我只是为排除添加 NOT IN 子句,它将不起作用,因为排除需要使用 AND。

我发现的唯一解决方案是在 mssql 中使用临时表和复制数据,您可能知道这非常慢。我在这里找到了许多解决方案,但没有一个能满足我的需要。

小提琴有我的数据库结构和当前进度。

标签: mysql

解决方案


SELECT m.title, GROUP_CONCAT(g.gname) genres
FROM movies m
JOIN genres g
JOIN genres_in_movies gm ON m.id = gm.movie_id AND g.id = gm.genre_id
GROUP BY m.title
HAVING SUM(g.gname = 'Romance')      -- must be present
   AND NOT SUM(g.gname = 'Comedy')   -- must be absent
/* AND SUM(g.gname IN ('Romance', 'Comedy'))     -- must present at least one of */
/* AND NOT SUM(g.gname IN ('Romance', 'Comedy')) -- must absent all of           */

推荐阅读