我的项目在laravel 5.4,mysql 5.7
上运行我有4张桌子
recipes (id, name)
ingredient_recipe (id, recipe_id, ingredient_id, amount)
ingredients (id, name, cat_id)
ingredient_category (id, name)
recipes
和ingredients
有many to many relations
到ingredient_recipe
表。每个食谱都可以有很多成分。每个成分的类别cat_id
都引用id
表中的ingredient_category
。
我需要选择所有配方的成分'类别ID等于请求的值,并将最匹配的值放在顶部。
例如,请求的成分类别ID为[23,56,76,102,11]
。
我们可以说食谱foo
的成分与23,56,76
匹配,bar
匹配23,56
和baz
匹配23
。他们应该被命令 - foo, bar, baz
。我该如何以这种方式订购?
这是我的sql代码
--select recipes
SELECT * from recipes where exists
--select recipe's ingredients
(select `ingredients`.`id`
from `ingredients`
inner join
`ingredient_recipe` on `ingredients`.`id` =
`ingredient_recipe`.`ingredient_id` where `recipes`.`id` =
`ingredient_recipe`.`recipe_id`
and exists
--select ingredient categories, where id ..
(select `ingredient_category`.`id`
from `ingredient_category`
where `ingredients`.`cat_id` = `ingredient_category`.`id`
and `id` IN (23,56,76,102,11)))
但是这段代码并没有“放置”大多数匹配的食谱。我知道我可以像在这个例子中那样选择然后过滤它们,但是在sql中有办法吗?
答案 0 :(得分:1)
您可以使用GROUP BY和左连接到类别表来获取类别数量的计数,然后对该计数进行排序。
SELECT
a.`id`,
a.`name`,
c.`id`.
c.`name`,
count(d.`id`) as `numcategories`,
GROUP_CONCAT(d.`name`)
FROM `recipes` a
JOIN `ingredient_recipe` b
ON a.`id` = b.`recipe_id`
JOIN `ingredients` c
ON b.`ingredient_id` = c.`id`
LEFT JOIN `ingredient_category` d
ON c.`cat_id` = d.`id`
GROUP BY a.`name`,c.`name`
ORDER BY count(d.`id`) DESC, a.`name`,c.`name`
答案 1 :(得分:1)
通过联结表ingredient_recipe
将配方表连接到配料表,然后按配方汇总。对于每个食谱,我们可以计算映射列表的成分数量,我们可以先输出更高的匹配项来订购结果集。
SELECT
r.id,
r.name,
COUNT(CASE WHEN i.cat_id IN (23, 56, 76, 102, 11) THEN 1 END) AS match_cnt
FROM recipes r
INNER JOIN ingredient_recipe ir
ON r.id = ir.recipe_id
INNER JOIN ingredients i
ON ir.ingredient_id = i.id
GROUP BY r.id
ORDER BY match_cnt DESC;
我们还可以添加HAVING
子句,例如过滤掉不符合最低匹配成分数量的食谱。我们还可以使用LIMIT
子句来限制匹配的总数。