2016-01-12 42 views
0

我有一個表product,其中有title(varchar)或availability(bool)等字段。INNER JOIN with NOT IN返回錯誤結果

用戶可以通過域名(product.title)搜索產品,但也可以應用特定的過濾器(如類型,生產者等)。 我使用SELECTINNER JOIN一起解決了這個問題。生成的查詢的示例如下所示:

SELECT z.* 
FROM product z 
WHERE (z.title LIKE "%bread%") 
AND z.availability = 1 
AND z.category IN (4,5,6); 

這很好。但是,產品上也貼有「過敏標籤」(如麩質)。 不幸的是,一種產品可以容納任何數量的「過敏標籤」,從而我需要使用的交聯表(crosslink__productXproduct_allergy_tag):

id int not null primary key auto_increment 
productId int 
allergyTagID int 

的標籤存儲在表product_allergy_tag,使用id作爲主鍵,和標籤的標題。 當然,對於那些無麩質產品搜索時,生成的查詢會再看看這樣的:

SELECT z.* 
FROM product z 
INNER JOIN crosslink__productXproduct_allergy_tag a ON z.id = a.productId 
WHERE (z.title LIKE "%bread%") 
AND z.availability = 1 
AND a.allergyTagId IN (15) 

(隨着15是麪筋標籤的ID)。

然而,如果我跑中相同的方式搜索如上所示,對於無麩質產品的搜索將結束顯示包含麪筋產品。

所以我想:我只需要反轉的邏輯:

相反的:

a.allergyTagId IN (15) 

這將是:

a.allergyTagId NOT IN (15) 

然而,然而,其原因我不明白,該查詢仍會返回一些帶有該過敏標籤的產品,但它不會全部返回。

我試圖通過測試不同的選項,並比較結果去的這個核心,但無濟於事。

有傳言說,我不是一個SQL行家。

有關此事的任何支持將會有所幫助。謝謝!

+1

您的查詢返回所有不含麩質的過敏原存在的產品。如果沒有任何過敏原,這將不會返回任何東西,它將不止一次地返回含有多種過敏原的產品,並且如果它們還具有第二(或第三)過敏原,它仍然會返回麩質產品。 – Thilo

+0

由於您在交叉點_productXproduct_allergy_tag上執行內部連接。您正在從含有某種過敏原的產品表中進行選擇。然後,你們縮小標題中的「麪包」的面積,並且過敏不是麪筋。由於某些產品可能含有多種過敏原,因此您必須加入一種產品的隨機抗原,通常這不會是麩質,因此它會被選中。顯然,這完全是你所需要的。我建議重新開始,進行邏輯連接並考慮每個添加的效果。 –

回答

1

的問題是,一個加入的作品,它會與每場比賽加入的方式,所以你會得到:

產品A - 過敏原 產品A - 過敏原乙 產品B - 過敏原Ç

您也沒有得到任何沒有過敏原的產品,因爲INNER JOIN需要至少選擇一種過敏原。

你想要的是加入並測試過敏原爲空。例如:

SELECT z.* FROM product z LEFT JOIN crosslink__productXproduct_allergy_tag a 
    ON z.id = a.productId AND a.allergyTagId IN (15) WHERE (z.title LIKE 
"%bread%") AND z.availability = 1 AND a.allergyTagId IS NULL 

這會在加入時進行過敏原檢查。如果匹配,它將爲每個匹配添加一行,將其設置爲匹配的ID的allergyTagId,如果匹配不匹配,則該列中將爲NULL。然後,過濾NULL列以獲得不會觸及任何過敏原的產品。

+0

起初它對我有意義,但看着它,我明白它並沒有考慮排除選定的過敏標籤?此外,它似乎查詢具有過敏標籤ID集AND AND過敏標籤ID爲空的條目。它根本不會返回任何東西? – SquareCat

+0

@SquareCat查詢在理解語義時有效:'t1 LEFT JOIN t2 ... WHERE t2.c1 IS NULL'表示「只包含來自t1的行,其中左連接在t2中找不到匹配的行。」我們不在* t2中尋找nulls *,我們在t2中查找可連接行中的nulls ......只有當沒有行包含我們想要證明的值時,纔會出現這種情況,只要t2.c1不是一個可結算的列......這正是你所要求的。 –

+1

邏輯上等同於這個答案,也許更直觀:'選擇Z * FROM產品z,其中(z.title LIKE 「麪包%%」)和z.availability = 1 AND NOT EXISTS(SELECT * FROM crosslink__productXproduct_allergy_tag一個 WHERE。 a.productId = z.id AND a.allergyTagId IN(15));' –

2
SELECT z.* FROM product z where z.title like "%bread%" and z.availability = 1 and z.id not in (Select productId from crosslink__productXproduct_allergy_tag a where a.allergyTagId = 15) 

編輯:你想要的是一個產品不包括在產品列表中有allergytag的15子查詢列表中發現的產品清單與15的allergytag,以及主要的查詢選擇所有的那些不是那些。