首先在mysql中选择最匹配的行

时间:2018-01-16 08:09:52

标签: mysql sql database laravel sorting

我的项目在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)

recipesingredientsmany to many relationsingredient_recipe表。每个食谱都可以有很多成分。每个成分的类别cat_id都引用id表中的ingredient_category

我需要选择所有配方的成分'类别ID等于请求的值,并将最匹配的值放在顶部。 例如,请求的成分类别ID为[23,56,76,102,11]。 我们可以说食谱foo的成分与23,56,76匹配,bar匹配23,56baz匹配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中有办法吗?

2 个答案:

答案 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子句来限制匹配的总数。