Reputation: 3028
I have three MySQL
tables: ingredients
, ingredient_in_recipe
and recipes
which can be INNER JOIN
ed to get ingredients in recipes. Also, the ingredients
table has a column vegetarian
. I want to get all recipes that are considered vegetarian, meaning that all ingredients for a given recipe must have set vegetarian
to 1 (it is a BOOL
/tinyint(1)
).
I have looked at queries using ALL
, HAVING NOT MAX
and other various stuff, but I cannot find a working solution. What is the best way to do this? Are there some solutions that are more efficient than others?
Extra (only relevant) table information:
mysql> DESCRIBE ingredients;
+-----------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(100) | NO | | NULL | |
| vegetarian | tinyint(1) | NO | | 0 | |
+-----------------+---------------+------+-----+---------+----------------+
mysql> DESCRIBE ingredient_in_recipe;
+---------------+------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------------+------+-----+---------+-------+
| recipe_id | int(11) | NO | | NULL | |
| ingredient_id | int(11) | NO | | NULL | |
+---------------+------------------------+------+-----+---------+-------+
mysql> DESCRIBE recipes;
+------------------------+----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+----------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | text | NO | | NULL | |
+------------------------+----------------------+------+-----+---------+----------------+
The start of my query is currently:
SELECT recipe.name, ingredient.name
FROM ingredients AS ingredient
INNER JOIN ingredient_in_recipe AS ir
ON ir.ingredient_id = ingredient.id
INNER JOIN recipes AS recipe
ON ir.recipe_id = recipe.id;
So I am missing a WHERE
, ALL
, IN
or something statement at the end.
Upvotes: 0
Views: 75
Reputation: 2283
Think of it this way.
So here's the set of all recipes with a non veg ingredient.
select
id
from
recipes,
ingredient_in_recipe,
ingredients
where
ingredient_in_recipe.recipe_id = recipes.id
and
ingredient_in_recipe.ingredient_id = ingredients.id
and
ingredients.vegetarian <> 1
Note: why are you using a tinyint to mark a boolen? USE Boolean to mark boolean.
Also your DB model is pretty good. Your naming is consistent and appropriate.
Now that we have the "non-vegitarian" recipes, we just subtract from a "set" perspective [as in set theory].
select
*
from
recipes
where
id NOT IN (
-- this subquery returns a set of IDs corresponding to non-vegitarian recipes.
select
id
from
recipes,
ingredient_in_recipe,
ingredients
where
ingredient_in_recipe.recipe_id = recipes.id
and
ingredient_in_recipe.ingredient_id = ingredients.id
and
ingredients.vegetarian <> 1
);
Upvotes: 1
Reputation: 20025
You can try the following:
SELECT r.name FROM recipes r WHERE r.id NOT IN (
SELECT ir.recipe_id FROM ingredient_in_recipe ir
INNER JOIN ingredients i ON ir.ingredient_id = i.id
WHERE i.vegeterian = 0
)
Upvotes: 1