基于一个值排除项的SQL查询

基于一个值排除项的SQL查询,sql,mysql,Sql,Mysql,我从一个表中提取一个项目列表,基于它们包含在另一个表中,如下所示: select fruit.id, fruit.name from fruit, fruit_rating where fruit_rating.fruit_id=fruit.id group by fruit.name; 这很好——它基本上生成了一个列表,列出了所有被某人评级的水果。但是现在,我想排除所有已经被一个特定用户评级的水果,所以我尝试了以下方法: select fruit.id, fruit.name from fr

我从一个表中提取一个项目列表,基于它们包含在另一个表中,如下所示:

select fruit.id, fruit.name from fruit, fruit_rating where fruit_rating.fruit_id=fruit.id group by fruit.name;
这很好——它基本上生成了一个列表,列出了所有被某人评级的水果。但是现在,我想排除所有已经被一个特定用户评级的水果,所以我尝试了以下方法:

select fruit.id, fruit.name from fruit, fruit_rating where fruit_rating.fruit_id=fruit.id and fruit_rating.user_id != 10 group by fruit.name;

没关系,但不完全正确。它显示除10以外的所有人对水果进行评级的结果,但如果用户1和10都对同一个水果进行了评级,它仍然显示该水果。有谁能告诉我如何构造一个查询,只显示用户10未评级的水果,而不管其他人对它们进行了评级?

我对您的查询进行了一些改进,使其更易于阅读,并添加了一个子查询,以过滤掉用户10评级的所有水果

... WHERE fruit_rating.fruit_id=fruit.id 
      and fruit.id not in 
          (select fruit_rating.fruit_id 
             from fruit_rating 
            where fruit_rating.user_id = 10)
select f.id, f.name 
from fruit f
inner join fruit_rating fr on
 fr.fruit_id = f.id 
where f.id not in (
    select id
    from fruit_rating
    where [user_id] = 10) 
group by fruit.name;

有一件事我还不是100%清楚:你想要的是所有没有被用户10评分的水果,还是仅仅是被其他人评分但没有被用户10评分的水果?e、 g.应该包括没有评级的水果吗

我想你想要的是所有的水果(包括未分级的),在这种情况下,诺亚和布朗斯通先生的答案并不完全是你想要的。如果你移除内部连接到水果等级,以及现在不需要的分组,他们的将包括未分级的水果。另一种避免子选择的方法是

select f.id, f.name 
from fruit f
left join fruit_rating fr on
  (f.id = fr.fruit_id)
  and (fr.user_id = 10)
where
  (fr.user_id is null)

也就是说,只为用户10对水果评级进行左联接(如果您愿意,可以选择联接),然后只返回未找到匹配项的行。

我的理解与Cowan不同,并且同意Noah

在以下位置查找所有水果: -用户10没有给它打分 -至少有一个其他用户对此进行了评分

然而,根据我的经验,使用NOT in可能会相当慢。因此,我通常更喜欢使用与Cowan相同的方式使用左连接进行过滤。这里有几个不同的选项,虽然我还没有时间在大型数据集上测试性能

SELECT
   [f].id,
   [f].name
FROM
   fruit           AS [f]
INNER JOIN
   fruit_rating    AS [fr]
      ON [fr].fruit_id = [f].id
GROUP BY
   [f].id,
   [f].name
HAVING
   SUM(CASE WHEN [fr_exclude].user_id = 10 THEN 1 ELSE 0 END) = 0


由于这只适用于一个用户,所以我也会考虑制作一个“用户排除”的表,然后左键加入……p>
SELECT
   [f].id,
   [f].name
FROM
   fruit           AS [f]
INNER JOIN
   fruit_rating    AS [fr]
      ON [fr].fruit_id = [f].id
LEFT JOIN
   excluded_users  AS [ex]
      AND [ex].user_id = [fr].user_id
GROUP BY
   [f].id,
   [f].name
HAVING
   MAX([ex].user_id) IS NULL

或者更冗长的东西,但我怀疑在具有适当索引的较大数据集上是最快的

SELECT
   [f].id,
   [f].name
FROM
   fruit           [f]
INNER JOIN
(
   SELECT
      fruit_id
   FROM
      fruit_rating
   GROUP BY
      fruit_id
)
   AS [rated]
      ON [rated].fruit_id = [f].id
LEFT JOIN
(
   SELECT
      [fr].fruit_id
   FROM
      fruit_rating    AS [fr]
   INNER JOIN
      excluded_users  AS [ex]
         ON [ex].user_id = [fr].user_id
   GROUP BY
      [fr].fruit_id
)
   AS [excluded]
      ON [rated].fruit_id = [excluded].fruit_id
WHERE
   [excluded].fruit_id IS NULL
GROUP BY
   [f].id,
   [f].name

是的,在这里速度很重要:)。但你写了整个查询,所以我想它也很有用。对不起:我想我最初的问题措辞有点松散。我实际上是在寻找诺亚和布朗斯通先生所建议的东西——也就是说,我只想要那些被用户10以外的人评过等级的水果。无论如何,谢谢你的回复。
SELECT
   [f].id,
   [f].name
FROM
   fruit           [f]
INNER JOIN
(
   SELECT
      fruit_id
   FROM
      fruit_rating
   GROUP BY
      fruit_id
)
   AS [rated]
      ON [rated].fruit_id = [f].id
LEFT JOIN
(
   SELECT
      [fr].fruit_id
   FROM
      fruit_rating    AS [fr]
   INNER JOIN
      excluded_users  AS [ex]
         ON [ex].user_id = [fr].user_id
   GROUP BY
      [fr].fruit_id
)
   AS [excluded]
      ON [rated].fruit_id = [excluded].fruit_id
WHERE
   [excluded].fruit_id IS NULL
GROUP BY
   [f].id,
   [f].name