你好我要选择唯一具有确切成分别名的菜肴吗? 例如: 成分别名表:
+----+----------+
| id | Name |
+----+----------+
| 22 | potato |
| 23 | rice |
| 29 | chicken |
+----+----------+
成分表:
+------+-----------+----------+-------+------+----------+
| id | name | proteins | carbs | fats | alias_id |
+------+-----------+----------+-------+------+----------+
| 3043 | Chicken 1 | 44.0 | 3.0 | 3.0 | 29 |
| 3025 | Rice 1 | 44.0 | 32.0 | 23 | 23 |
| 3024 | Rice 2 | 23.0 | 22.0 | 33.0 | 23 |
| 3042 | Chicken 2 | 22.0 | 22.0 | 3.0 | 29 |
| 3022 | Potato 1 | 22.0 | 22.0 | 32.0 | 22 |
| 3021 | Potato 2 | 20.0 | 30.0 | 40.0 | 22 |
| 3041 | Chicken 3 | 11.0 | 11.0 | 11.0 | 29 |
| 3026 | Rice 3 | 1.0 | 1.0 | 1.0 | 23 |
| 3023 | Potato 3 | 1.0 | 2.0 | 3.0 | 22 |
+------+-----------+----------+-------+------+----------+
餐桌餐:
+----+-----------------------------------------+
| id | name |
+----+-----------------------------------------+
| 1 | Meal with Chicken 1 and Rice 1 |
| 2 | Meal with Chicken 1 and Rice 2 |
| 3 | Meal with Chicken 2 Potato 1 |
| 4 | Meal with Chicken 2 Potato 1 and Rice 1 |
+----+-----------------------------------------+
餐食成分:
+-------+---------+---------------+--------+------+
| id | meal_id | ingredient_id | weight | role |
+-------+---------+---------------+--------+------+
| 13366 | 1 | 3043 | 13 | 1 |
| 13367 | 1 | 3025 | 1 | 1 |
| 13368 | 2 | 3043 | 12 | 2 |
| 13369 | 2 | 3024 | 8 | 3 |
| 13370 | 3 | 3042 | 22 | 1 |
| 13371 | 3 | 3022 | 1 | 1 |
| 13372 | 4 | 3042 | 3 | 1 |
| 13373 | 4 | 3022 | 3 | 3 |
| 13374 | 4 | 3024 | 2 | 2 |
+-------+---------+---------------+--------+------+
我如何仅进餐,其中的食材只有且别名为土豆和鸡肉?在我的示例中,结果必须是ID为3的餐点,餐点为鸡肉2马铃薯1?
答案 0 :(得分:2)
您需要按膳食分组连接所有4个表,并将条件放入HAVING子句:
select m.id, m.name
from ingredient_alias ia
inner join ingredient i on i.alias_id = ia.id
inner join meal_ingredient mi on mi.ingredient_id = i.id
inner join meal m on m.id = mi.meal_id
group by m.id, m.name
having
count(distinct ia.name) = 2
and
sum(ia.name not in ('potato', 'chicken')) = 0
请参见demo。
结果:
| id | name |
| --- | -------------------------------- |
| 3 | Meal with Chicken 2 and Potato 1 |
答案 1 :(得分:0)
这是一种方法:
select m.meal_id
from meal_ingredient m join
ingredient i
on m.ingredient_id = i.id left join
ingredient_alias ia
on ia.id = i.ingredient_alias_id
group by m.meal_id
having count(ia.id) = count(*) and -- all ingredients in meal match list
count(*) = (select count(*) from ingredient_alias) -- all ingredients in list are present
如果可以重复,则第二个条件应该是count(distinct m.ingredient_id)
,而不是count(*)
。
答案 2 :(得分:0)
您正在处理被称为成分别名的成分类别。例如。您有“米”类别,可以是“白米”,“红米”以及其他任何大米。您正在寻找的食物正好包含一组给定的成分类别,例如'米饭和鸡肉'。在最坏的情况下,您的餐食包含多次类别。可以说一顿饭包括“鸡肉”,“白米饭”和“红米饭”。尽管具有三种成分,但该餐只包含两种成分。
从MySQL 8开始:
with ia as
(
select id from ingredient_alias where name in ('potato', 'chicken')
)
select *
from meal
where id in
(
select mi.meal_id
from meal_ingredient mi
join ingredient i on i.id = mi.ingredient_id
left join ia on ia.id = i.alias_id
group by mi.meal_id
having count(distinct ia.id) = count(distinct i.alias_id)
and count(distinct ia.id) = (select count(*) from ia)
);
对于较旧的版本,请删除WITH
子句,然后编写左联接和不带左联接的子查询(或者算一下自己,并用该数字替换子查询)。
答案 3 :(得分:0)
我有一个简单的方法: -加入4个表格并选择成分名称中未包含的餐点ID(“土豆”,“鸡肉”) -在上方未找到的ID中选择ID不作为的餐点。 这里的代码(SQL Server):
select * from test.dbo.meal where test.dbo.meal.id not in (
select m.id from test.dbo.meal m
inner join test.dbo.meal_ingredient mi on m.id = mi.meal_id
inner join test.dbo.Ingredient i on i.id = mi.ingredient_id
inner join test.dbo.Ingredient_alias ia on ia.id = i.Ingredient_alias_id
where ia.name not in ('potato', 'chicken')
)