我从一个表中提取项目列表,基于它们被包含在另一个表中,如下所示:
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未评级的水果,无论其他人对它们进行了评分吗?
答案 0 :(得分:6)
... 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)
答案 1 :(得分:4)
我和Cowan的看法不一样,并且同意诺亚......
查找所有水果: - 用户10没有给它评分 - 至少有一个其他用户评价了它
但是,根据我的经验,使用NOT IN可能会非常慢。因此,我通常更喜欢使用LEFT JOIN以与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
SELECT
[f].id,
[f].name
FROM
fruit AS [f]
INNER JOIN
fruit_rating AS [fr]
ON [fr].fruit_id = [f].id
LEFT JOIN
fruit_rating AS [fr_exclude]
ON [fr_exclude].fruit_id = [fr].fruit_id
AND [fr_exclude].user_id = 10
GROUP BY
[f].id,
[f].name
HAVING
MAX([fr_exclude].user_id) IS NULL
由于这只适用于一个用户,我还会考虑制作一个“用户排除”和LEFT JOIN的表格,而不是......
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
答案 2 :(得分:3)
我对您的查询进行了一些改进,使其更容易阅读,并添加了一个子查询来过滤掉用户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;
答案 3 :(得分:1)
对我来说,有一件事情并不是100%明确:你想要所有水果没有被用户10评级,或只是水果已被其他人评定但不是用户10?例如应该包括没有评级的水果吗?
我想你想要所有的水果(包括未评级的),在这种情况下,诺亚和布朗斯通先生的答案并不是你所追求的。如果你删除内部联接到fruit_rating,以及现在不必要的组,他们将包括未分级的水果。另一种避免子选择的方法是
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进行左连接(可选连接,如果你愿意)到水果评级,然后只返回未找到匹配的行。