搜索不在关系n:m中的多行

时间:2018-10-02 11:16:20

标签: mysql sql

类似的问题here

与上述问题非常相似,但有一点点不同,我需要在电影列表中找到未曾看过至少一部电影的用户列表。

假设两个表“ movies”和“ users”之间存在一个n:m关系,一个表“ seen”描述了这种关系。

我需要从给定列表中找出任意数量的给定用户,以及任意数量的给定电影所有用户 ,但没有观看过至少一部电影。

在单个查询中可以实现吗?我不知道该怎么做。

编辑:这是一个尝试解决该问题的演示,所涉及的问题是它返回的用户尚未查看给定列表中的所有电影。我们需要的是一个从未观看过以下列表中的任何电影的用户:http://rextester.com/DEIH39789

3 个答案:

答案 0 :(得分:1)

考虑“用户”和“电影”表之间的n:m关系,其中包含中间表。

SELECT * FROM Users u WHERE NOT EXISTS (SELECT UserId FROM Seen s WHERE s.UserId = u.ID)

此查询将返回在Seen表中没有任何相关记录的Users

答案 1 :(得分:1)

我想说些类似的方法,即将用户表左连接到可见表(并将该表连接到电影表)。

(由于MatBailie的评论而修改了代码)

在JOIN子句中添加列表限制(而不是MatBailie向我指出的WHERE子句),您会得到类似的信息(以下代码在SQL-Server上也应适用,但对MySql也应如此) ):

SELECT COUNT(Users.ID)
FROM Users
LEFT JOIN Seen ON Users.ID = Seen.UserID AND Users.something IN (list)
LEFT JOIN Movies ON Seen.MovieID = Movie.ID AND Movies.something IN (list)
WHERE Movies.ID IS NULL
GROUP BY User.ID -- <-- This is probably optional

但是由于通常有多种方法可以得到相同的结果,因此我以前的答案经过了调整:

SELECT COUNT(Users.ID)
FROM Users
LEFT JOIN Seen ON Users.ID = Seen.UserID
LEFT JOIN Movies ON Seen.MovieID = Movie.ID
WHERE (Users.something IN (list) OR Users.something IS NULL)
  AND (Movies.something IN (list) OR Movies.something IS NULL)
  AND Movies.ID IS NULL
GROUP BY User.ID -- <-- This is probably optional

第三次尝试:获取列表中已看过其中一部电影的所有用户ID。接下来,获取列表中的所有用户ID,并减去看过其中一部电影的用户ID。知道对于大数据集(几千个不大),此查询可能会变慢。为了测试它,我从看到的列表中删除了“ userid = 2和movieid = 3”,否则我不会得到结果。现在,我发现尼克没有看过前三部电影中的任何一部(请参考您的右摄示例)

SELECT *
FROM musers
WHERE musers.id IN (1,2,3)
  AND musers.id NOT IN (
    SELECT musers.id
    FROM musers
    JOIN Seen ON musers.ID = Seen.UserID 
    JOIN Movies ON Seen.MovieID = movies.ID 
    WHERE movies.id IN (1,2,3) )

答案 2 :(得分:1)

此查询应为您提供所需的结果。我假设您的基本结构是:

users (id int, name varchar(20));
movies (id int, title varchar(20));
seen (user_id int, movie_id int);

SELECT u.*
FROM users u
LEFT JOIN seen s
ON s.user_id = u.id AND s.movie_id IN (movielist)
WHERE s.user_id IS NULL AND u.id IN (userlist)

WHERE s.user_id IS NULL条件意味着LEFT JOIN为您提供了movielist中没有看过电影的所有用户,而{{1} }然后将结果限制为仅该组用户。 您可以修改u.id IN (userlist)子句以匹配您感兴趣的电影和用户列表。我制作了一个小的demo on Rextester

更新

我误解了这个问题;对于没有看过列表中一部(或多部)电影的用户来说,理想的结果是。此查询解决了该问题:

IN

SELECT u.* FROM musers u LEFT JOIN seen s ON s.user_id = u.id AND s.movie_id IN (1, 2) WHERE u.id IN (1, 2, 3) GROUP BY u.id HAVING COUNT(s.movie_id) < 2 JOIN的结果是用户(1、2、3)和他们看过的电影。如果他们看过电影列表WHERE中的所有电影,则(1, 2)中电影的COUNT为2,否则,如果他们没有看过一个(或多个)电影,小于2。这是updated demo。请注意,当电影列表的长度更改时,seen子句中的2必须更改以匹配电影列表的长度。