Reputation: 9
I have these tables
Table FoodName - Table FoodIngredients - Table FoodDescrip
ID | Name - ID | Ingredient - ID | Descrip | IDFoodN | IDIngred
01 | A - 001 | AA - 01 | abcb | 01 | 001
02 | B - 002 | BB - 02 | abcb | 01 | 002
003 | CC 03 | abcb | 01 | 003
04 | abcb | 02 | 001
05 | abcb | 02 | 003
I tried
Select
f.Name
From
f.FoodName
INNER JOIN
FoodDescrip D ON f.ID = D.ID
INNER JOIN
FoodIngredients I ON I.ID = D.ID
WHERE
Ingredient LIKE NOT ='BB'"
I need to know that food that doesn't have the ingredient BB, but I need to do the search by the name of the ingredient not by the id. I tried to use Ingredient NOT LIKE but it doesn't work. (I'm using Inner JOIN)
Upvotes: 1
Views: 93
Reputation: 672
I would use NOT EXISTS for this one. (Or NOT IN like AB_87’s answer.) Your FoodDescrip table is a cross reference between food and ingredients. You want every food that doesn’t have a cross reference to the BB ingredient.
SELECT f.Name
FROM FoodName f
WHERE NOT EXISTS
(
SELECT *
FROM FoodDescrip d
JOIN FoodIngredients i ON i.ID = d.IDIngred
AND i.Ingredient = ‘BB’
AND d.IDFoodN = f.ID
)
“Select all food we’re not exists a cross reference between that food and the BB ingredient.”
The outer query selects from the food table so you can return the food name. The subquery in the NOT EXISTS joins out from the cross reference table to the ingredient table so you can find the ones with the BB name, and is also filtered down to only the food in the outer query. So, if any BBs are found to exist in the subquery linked to the food, the NOT EXISTS will be false, and the food will be removed from the result by the WHERE clause.
This can be tweaked slightly to use NOT IN instead of NOT EXISTS. It’s basically the exact same approach. Here’s that:
SELECT f.Name
FROM FoodName f
WHERE f.ID NOT IN
(
SELECT d.IDFoodN
FROM FoodDescrip d
JOIN FoodIngredients i ON i.ID = d.IDIngred
AND i.Ingredient = ‘BB’
)
“Select all foods where the ID is not in the list of food IDs linked to the BB ingredient in the cross reference table.”
I prefer these over Tim’s approach because I think they read nicer. Also, they may perform better because they can throw out a food from the results as soon as they find one reference to the BB ingredient. Tim’s method of conditional aggregation requires counting all the matches and seeing if the result is equal to vs. greater than zero.
Upvotes: 1
Reputation: 1156
You can try this. Get FoodId which has ingredient 'BB' and then retrieve all food which do not have FoodId retrieved earlier.
SELECT *
FROM FoodName
WHERE ID NOT IN ( SELECT d.IDFoodN
FROM FoodIngredients i
JOIN FoodDescrip d ON i.ID = d.IDIngred
WHERE i.Ingredient = 'BB' );
Upvotes: 1
Reputation: 520898
One approach uses conditional aggregation to check for the ingredient:
SELECT
f1.ID, f1.Name
FROM FoodName f1
INNER JOIN FoodDescrip f2
ON f1.ID = f2.IDFoodN
INNER JOIN FoodIngredients f3
ON f2.IDIngred = f3.ID
GROUP BY
f1.ID, f1.Name
HAVING
SUM(CASE WHEN f3.Ingredient = 'BB' THEN 1 ELSE 0 END) = 0
Upvotes: 2