Considere este exemplo...
SELECT * FROM recipes;
+-----------+---------------------------------+
| recipe_id | recipe |
+-----------+---------------------------------+
| 6 | Beans & Macaroni |
| 9 | Beans on Jacket Potato |
| 3 | Beans on Toast |
| 10 | Cheese & Beans on Jacket Potato |
| 4 | Cheese & Beans on Toast |
| 2 | Cheese on Toast |
| 1 | Macaroni & Cheese |
| 12 | Peanut Butter on Toast |
| 5 | Toast & Jam |
+-----------+---------------------------------+
SELECT * FROM recipe_ingredient;
+-----------+---------------+
| recipe_id | ingredient_id |
+-----------+---------------+
| 1 | 1 |
| 1 | 2 |
| 2 | 2 |
| 2 | 4 |
| 3 | 3 |
| 3 | 4 |
| 4 | 2 |
| 4 | 3 |
| 4 | 4 |
| 5 | 4 |
| 5 | 5 |
| 6 | 1 |
| 6 | 3 |
| 9 | 3 |
| 9 | 6 |
| 10 | 2 |
| 10 | 3 |
| 10 | 6 |
| 12 | 4 |
| 12 | 7 |
+-----------+---------------+
SELECT * FROM ingredients;
+---------------+---------------+
| ingredient_id | ingredient |
+---------------+---------------+
| 3 | Beans |
| 2 | Cheese |
| 6 | Jacket Potato |
| 5 | Jam |
| 1 | Macaroni |
| 7 | Peanut Butter |
| 4 | Toast |
+---------------+---------------+
O seguinte retorna uma lista de todas as receitas e os ingredientes necessários para construí-las...
SELECT r.*
, i.*
FROM recipes r
JOIN recipe_ingredient ri
ON ri.recipe_id = r.recipe_id
JOIN ingredients i
ON i.ingredient_id = ri.ingredient_id;
+-----------+---------------------------------+---------------+---------------+
| recipe_id | recipe | ingredient_id | ingredient |
+-----------+---------------------------------+---------------+---------------+
| 6 | Beans & Macaroni | 1 | Macaroni |
| 6 | Beans & Macaroni | 3 | Beans |
| 9 | Beans on Jacket Potato | 3 | Beans |
| 9 | Beans on Jacket Potato | 6 | Jacket Potato |
| 3 | Beans on Toast | 3 | Beans |
| 3 | Beans on Toast | 4 | Toast |
| 10 | Cheese & Beans on Jacket Potato | 2 | Cheese |
| 10 | Cheese & Beans on Jacket Potato | 3 | Beans |
| 10 | Cheese & Beans on Jacket Potato | 6 | Jacket Potato |
| 4 | Cheese & Beans on Toast | 2 | Cheese |
| 4 | Cheese & Beans on Toast | 3 | Beans |
| 4 | Cheese & Beans on Toast | 4 | Toast |
| 2 | Cheese on Toast | 2 | Cheese |
| 2 | Cheese on Toast | 4 | Toast |
| 1 | Macaroni & Cheese | 1 | Macaroni |
| 1 | Macaroni & Cheese | 2 | Cheese |
| 12 | Peanut Butter on Toast | 4 | Toast |
| 12 | Peanut Butter on Toast | 7 | Peanut Butter |
| 5 | Toast & Jam | 4 | Toast |
| 5 | Toast & Jam | 5 | Jam |
+-----------+---------------------------------+---------------+---------------+
Agora vamos supor que temos uma despensa contendo Queijo, Feijão e Torrada. O que podemos construir usando APENAS esses ingredientes?
SELECT r.*
, SUM(CASE WHEN ingredient IN ('Cheese','Beans','Toast') THEN 1 ELSE 0 END) x
, COUNT(*) y
FROM recipes r
JOIN recipe_ingredient ri ON ri.recipe_id = r.recipe_id
JOIN ingredients i ON i.ingredient_id = ri.ingredient_id
GROUP
BY r.recipe_id;
+-----------+---------------------------------+------+---+
| recipe_id | recipe | x | y |
+-----------+---------------------------------+------+---+
| 1 | Macaroni & Cheese | 1 | 2 |
| 2 | Cheese on Toast | 2 | 2 | <--
| 3 | Beans on Toast | 2 | 2 | <--
| 4 | Cheese & Beans on Toast | 3 | 3 | <-- *
| 5 | Toast & Jam | 1 | 2 |
| 6 | Beans & Macaroni | 1 | 2 |
| 9 | Beans on Jacket Potato | 1 | 2 |
| 10 | Cheese & Beans on Jacket Potato | 2 | 3 |
| 12 | Peanut Butter on Toast | 1 | 2 |
+-----------+---------------------------------+------+---+
x = y : recipes use only those ingredients found in the pantry.
x = y = total no of ingredients in pantry : recipes using EXACTLY the ingredients found in the pantry
Isso pode ser reescrito assim...
SELECT r.*
FROM recipes r
JOIN recipe_ingredient ri ON ri.recipe_id = r.recipe_id
JOIN ingredients i ON i.ingredient_id = ri.ingredient_id
GROUP
BY r.recipe_id
HAVING SUM(CASE WHEN ingredient IN ('Cheese','Beans','Toast') THEN 1 ELSE 0 END) = COUNT(*);