2009-01-08 63 views
3

我拉项目的列表从一个表,他们的存在的包含在另一个表的基础上的基础上的项目,如:SQL查询来排除一个值

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评分的水果的查询,而不管其他人是否对他们进行了评分?

回答

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) 
+0

你打我吧! – Noah 2009-01-08 21:59:20

+0

是的,这里的速度问题:)。但是你写了整个查询,所以我猜它也很有用。 – Rockcoder 2009-01-08 22:06:34

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; 
1

一两件事,ISN水果对我而言,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,然后只返回行,其中一个比赛WASN 'T发现。

4

我从考恩读此不同,与诺亚同意...

找到所有的水果,其中: - 用户 - 没有评分 - ATLEAST一个其他用户没有评分

然而,根据我的经验,使用NOT IN可能会很慢。所以,我通常更喜欢用与Cowan相同的方式使用LEFT JOIN进行过滤。这里有几个不同的选择,虽然我还没有来得及测试的大型数据集的性能...

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