[英]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.