继我的查询yesterday之后,我重新构建了我的食谱数据库,如下所示:
类别
cid | category_name
1 | desserts
2 | cakes
3 | biscuits
配方
id | recipe_name
1 | black forest cake
2 | angel cake
3 | melting moments
4 | croquembouche
5 | crepes suzette
成分
iid | ingredient_name
1 | self-raising flour
2 | milk
3 | chocolate
4 | baking powder
5 | plain flour
6 | eggs
recipe_categories
recipe_id | category_id
1 | 1
4 | 1
5 | 1
1 | 2
2 | 2
3 | 3
4 | 3
recipe_ingredients
recipe_id | ingredient_id
1 | 1
2 | 1
4 | 1
1 | 2
2 | 2
3 | 2
5 | 2
1 | 3
2 | 3
1 | 4
3 | 5
4 | 5
我的查询需要按类别返回配方,其中列出的成分使用
来分隔成分(可能使用GROUP_CONCAT(i.ingredient_name分隔符'
')输出,如昨天建议的那样。)
因此,对甜点的查询将输出:
black forest cake:
self-raising flour
milk
chocolate
croquembouche:
self-raising flour
plain flour
crepes suzette:
milk
plain flour
我知道我必须加入recipe_ingredients和食谱和成分以及搜索类别,但我真的很想如何做到这一点。
答案 0 :(得分:2)
查询:
SELECT A.recipe_name, GROUP_CONCAT(ingredient_name) AS ingredient_names
FROM recipes A
LEFT JOIN recipe_ingredients B ON A.id = B.recipe_id
LEFT JOIN ingredients C ON B.ingredient_id = C.iid
LEFT JOIN recipe_categories D ON A.id = D.recipe_id
LEFT JOIN categories E ON D.category_id = E.cid
WHERE category_id = <serach_id>
GROUP BY id
结果:
+-------------------+-------------------------------------------------+
| recipe_name | ingredient_names |
+-------------------+-------------------------------------------------+
| black forest cake | chocolate,baking powder,self-raising flour,milk |
| angel cake | self-raising flour,milk,chocolate |
| melting moments | milk,plain flour |
| croquembouche | self-raising flour,plain flour |
| crepes suzette | milk |
+-------------------+-------------------------------------------------+
以下是您要求使用GROUP_CONCAT的内容。每种成分由,
答案 1 :(得分:1)
我发现你可以通过一次一步地分解它们来理解事物。
首先,让我们抓住我们的甜点。
SELECT categories.cid
FROM categories
WHERE category_name = 'desserts'
现在让我们通过将它们粘贴在结果的左侧来抓住所有沙漠的食谱。对于类别中的每个匹配行,recipe_categories中可以有一个或多个匹配的行。对于recipe_categories中的每个匹配行,配方中可以有一个或多个匹配的行。
SELECT categories.cid, recipes.recipe_name
FROM categories
LEFT JOIN recipe_categories ON (recipe_categories.category_id = categories.cid)
LEFT JOIN recipes ON (recipes.rid = recipe_categories.recipe_id)
WHERE category_name = 'desserts'
最后,让我们在左边附上我们的食材。对于我们到目前为止的每个匹配行(我们现在都在配方中),我们可以在recipe_ingredients中有一个或多个匹配项,然后在配方中再次匹配一个或多个匹配项。
SELECT recipes.recipe_name, ingredients.ingredient_name
FROM categories
LEFT JOIN recipe_categories ON (recipe_categories.category_id = categories.cid)
LEFT JOIN recipes ON (recipes.rid = recipe_categories.recipe_id)
LEFT JOIN recipe_ingredients ON (recipe_ingredients.recipe_id = recipes.rid)
LEFT JOIN ingredients ON (ingredients.iid = recipe_ingredients.ingredient_id)
WHERE category_name = 'desserts'
到目前为止我?
现在,已经很晚了,我还没有测试过这个,但它应该返回你正在寻找的数据。事实上,我可能完全使用错误的连接类型来正确完成此操作。如果我错了,我肯定评论中有人会纠正我。
此不会做的是返回您希望格式化的数据。让我们在查询的最后一次迭代中添加一些id字段。
SELECT recipes.rid, recipes.recipe_name, ingredients.iid, ingredients.ingredient_name
FROM categories
LEFT JOIN recipe_categories ON (recipe_categories.category_id = categories.cid)
LEFT JOIN recipes ON (recipes.rid = recipe_categories.recipe_id)
LEFT JOIN recipe_ingredients ON (recipe_ingredients.recipe_id = recipes.rid)
LEFT JOIN ingredients ON (ingredients.iid = recipe_ingredients.ingredient_id)
WHERE category_name = 'desserts'
让我们将数据收集到一个多维数组中。让我们假装我们正在使用PDO。
$query = '...';
$sh = $db->prepare($query);
$sh->execute();
$recipes = array();
while($row = $sh->fetch(PDO::FETCH_ASSOC)) {
// For each row in the result set, check to see if we've looked at this recipe.
if(!array_key_exists( $row['rid'], $recipes )) {
// If we haven't, let's initialize the row with the recipe name
// and a place to stick each ingredient.
$recipes[ $row['rid'] ] = array(
'recipe_name' => $row['recipe_name'],
'ingredients' => array()
);
}
// Place this ingredient with the proper recipe.
$recipes[ $row['rid'] ]['ingredients'][ $row['iid'] ] = $row['ingredient_name'];
}
结果应该是这样的:
array(
1 => array(
'recipe_name' => 'black forest cake',
'ingredients' => array(
'1' => 'self-raising flour',
'2' => 'milk',
...
)
)
)
从这个结构中,你可以做你想做的事。
答案 2 :(得分:0)
我会留给你弄清楚如何正确地格式化它,但是要开始你需要一起加入成分和食谱表,但搜索类别(也加入)。
我发现执行后者的最简单/最好的方法是使用IN
子句(EXISTS
也可以)。例如:
SELECT *
FROM recipes
LEFT OUTER JOIN recipe_ingredients ON recipe.recipe_id = recipe_ingredients.recipe_id
WHERE recipes.id IN (SELECT recipe_categories.recipe_id
FROM categories
INNER JOIN recipe_categories ON categories.cid = recipe_categories.category_id
WHERE categories.category_name = @search_term)
请注意,除非您只搜索一个类别,否则当食谱包含多个匹配类别时,执行直接JOIN将生成多行,因此IN
/ EXISTS
最佳。