views:

38

answers:

5

I have four tables:

cuisines(id, name);

recipes(id, cuisine_id, name, picture);

ingredients(id, name);

ingredients_recipes(ingredient_id, recipe_id);

the last table references the Many-To-Many relationship between recipes and ingredients. How can I select all cuisines which contain tomatoes (i.e. the cuisine has recipes which have ingredients which are called "tomatoes")?

I am using this in SQLite but I guess it's the same in all SQL languages?

+3  A: 

You may want to try INNER JOINing all four tables, as in the following example:

SELECT      DISTINCT c.name
FROM        cuisines AS c
INNER JOIN  recipes AS r ON (r.cuisine_id = c.id)
INNER JOIN  ingredients_recipes AS ir ON (ir.recipe_id = r.id)
INNER JOIN  ingredients AS i ON (i.id = ir.ingredient_id)
WHERE       i.name = 'tomatoes';
Daniel Vassallo
Wouldn't this give you repeating cuisine names for cuisines that have multiple recipes with tomatoes? Is `SELECT DISTINCT c.name` needed?
markusk
@markusk: Yep good point. Either `DISTINCT` or a `GROUP BY`. Updated my answer.
Daniel Vassallo
A: 

Join them all according to the foreign keys, filter on ingredient_name = 'Tomatoe', group by all columns of the cuisines table you're interested in.

SELECT cuisine.id, cuisine.name
  FROM cuisine
  INNER JOIN recipe on recipe.cuisine_id = cuisine.id
  INNER JOIN ingredients_recipes ir ON ir.recipe_id = recipe.id
  INNER JOIN ingredients on ingredients.id = ir.ingredient_id
  WHERE ingredients.name = 'Tomatoe'
  GROUP BY cuisine.id, cuisine.name
tdammers
A: 

Subquery variant:

SELECT name
FROM cuisines
WHERE id IN (
    SELECT cuisine_id 
    FROM recipes r 
    JOIN ingredients_recipes ir ON r.id = ir.recipe_id
    JOIN ingredients i ON ir.ingredient_id = i.id
    WHERE i.name = 'Tomatoes'
)
markusk
A: 

I'd suggest using subqueries instead of the joins. Something like...

SELECT *
    FROM cuisine
    WHERE cuisine_id IN (
             SELECT cuisine_id
                 FROM recipe
                 WHERE recipe_id IN (
                         SELECT recipe_id
                             FROM recipe_ingredients
                             WHERE ingredient_id IN (
                                        SELECT id
                                        FROM ingredients
                                        WHERE TOUPPER(name) LIKE '%TOMATO%')));

In any case, I think you have to be careful with the match on the word; more so than other correspondents have been, as you don't want to miss ingredients like 'Four small tomatoes' or 'One large tomato' or 'Tomato puree'.

Brian Hooper
hi, thanks for that. What is the advantage of subqueries over joins?
ChrisB
I find subqueries easier to understand than joins, and less error-prone, although I suspect I am in a minority in that respect. Admittedly an extended nest like the above isn't a particularly appealing example. You do whatever you like best. It is often said that subqueries are slower than joins; I have never found that to be so. The query optimiser is quite capable of rewriting a subquery as a join if it thinks proper.
Brian Hooper
A: 

EXISTS variant:

SELECT name
FROM cuisines c
WHERE EXISTS
(   SELECT NULL 
    FROM recipes r 
    JOIN ingredients_recipes ir ON r.id = ir.recipe_id
    JOIN ingredients i ON ir.ingredient_id = i.id and i.name = 'tomatoes'
    WHERE r.cuisine_id = c.id
)
Mark Bannister