簡體   English   中英

SQL查詢以基於一個值排除項目

[英]SQL query to exclude items on the basis of one value

我正在從一個表中提取項目列表,基於它們被包含在另一個表中,如下所示:

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未評級的水果,無論其他人對它們進行了評分?

... 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)

我和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

我稍微改進了你的查詢,使其更容易閱讀,並添加了一個子查詢來過濾掉用戶評價的所有水果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評價過的水果嗎? 例如,應該包括沒有評級的水果嗎?

你想要所有的水果(包括未評級的),在這種情況下,諾亞和布朗斯通先生的答案並不是你所追求的。 如果你刪除內部聯接到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執行左連接(可選連接,如果您願意)到水果評級,然后僅返回未找到匹配的行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM