Sql 如何查找表中在给定列表中唯一具有相关行的所有行?
我有三张桌子。可以这样想:Sql 如何查找表中在给定列表中唯一具有相关行的所有行?,sql,sql-match-all,Sql,Sql Match All,我有三张桌子。可以这样想: Recipes id | name 1 | Cookies 2 | Soup ... Ingredients id | name 1 | flour 2 | butter 3 | chicken ... Recipe_Ingredient recipe_id | ingredient_id 1 | 1 1 | 2 2 | 3 希望你能明白。
Recipes
id | name
1 | Cookies
2 | Soup
...
Ingredients
id | name
1 | flour
2 | butter
3 | chicken
...
Recipe_Ingredient
recipe_id | ingredient_id
1 | 1
1 | 2
2 | 3
希望你能明白。我想要的是一个查询,在那里我可以找到所有配方,其中的成分是一组给定成分的子集
我的想法是,我希望有一份清单,列出所有我手头上的东西(当然不是所有我手头上的东西)
我尝试用不同级别的子查询和与EXISTS相关的子查询来实现这一点,但没有成功。我也尝试过使用HAVING和COUNT,但这似乎只适用于我想要的东西使用了我手头上所有的成分。如果有效,测试一下。假设您的(唯一)配料id在名为“配料”的表中可用,此查询应显示包含完整配料的配方id:
mysql>
mysql> select * from ingredients;
+------+---------------+-----------+
| id | name | available |
+------+---------------+-----------+
| 1 | salt | n |
| 2 | sugar | n |
| 3 | flour | n |
| 4 | butter | n |
| 5 | vanilla | n |
| 6 | baking powder | n |
| 7 | egg | n |
+------+---------------+-----------+
7 rows in set (0.00 sec)
mysql> select * from recipes;
+------+---------------+
| id | name |
+------+---------------+
| 1 | cookie |
| 2 | soup |
| 3 | xtreme flavor |
+------+---------------+
3 rows in set (0.00 sec)
mysql> select * from recipe_ingredient;
+-----------+---------------+
| recipe_id | ingredient_id |
+-----------+---------------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 1 | 5 |
| 1 | 6 |
| 1 | 7 |
| 2 | 1 |
| 2 | 7 |
| 3 | 4 |
| 3 | 3 |
+-----------+---------------+
11 rows in set (0.00 sec)
mysql>
mysql> update ingredients set available = 'n';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 7 Changed: 0 Warnings: 0
mysql>
mysql> update ingredients set available = 'y'
-> where id in (1,2,3,4,5,6,7);
Query OK, 7 rows affected (0.00 sec)
Rows matched: 7 Changed: 7 Warnings: 0
mysql>
mysql> select recipes.name from
-> (select recipe_id, available from
-> recipe_ingredient,
-> ingredients
-> where ingredient_id = ingredients.id
-> group by recipe_id, available) x, recipes
-> where recipes.id = x.recipe_id
-> group by x.recipe_id
-> having count(*) = 1
-> and max(x.available) = 'y';
+---------------+
| name |
+---------------+
| cookie |
| soup |
| xtreme flavor |
+---------------+
3 rows in set (0.06 sec)
mysql>
mysql> update ingredients set available = 'n';
Query OK, 7 rows affected (0.00 sec)
Rows matched: 7 Changed: 7 Warnings: 0
mysql>
mysql> update ingredients set available = 'y'
-> where id in (1,7);
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql>
mysql> select recipes.name from
-> (select recipe_id, available from
-> recipe_ingredient,
-> ingredients
-> where ingredient_id = ingredients.id
-> group by recipe_id, available) x, recipes
-> where recipes.id = x.recipe_id
-> group by x.recipe_id
-> having count(*) = 1
-> and max(x.available) = 'y';
+------+
| name |
+------+
| soup |
+------+
1 row in set (0.06 sec)
mysql>
mysql>
mysql> update ingredients set available = 'n';
Query OK, 2 rows affected (0.00 sec)
Rows matched: 7 Changed: 2 Warnings: 0
mysql>
mysql> update ingredients set available = 'y'
-> where id in (4,3);
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql>
mysql> select recipes.name from
-> (select recipe_id, available from
-> recipe_ingredient,
-> ingredients
-> where ingredient_id = ingredients.id
-> group by recipe_id, available) x, recipes
-> where recipes.id = x.recipe_id
-> group by x.recipe_id
-> having count(*) = 1
-> and max(x.available) = 'y';
+---------------+
| name |
+---------------+
| xtreme flavor |
+---------------+
1 row in set (0.05 sec)
mysql>
mysql>
mysql> update ingredients set available = 'n';
Query OK, 3 rows affected (0.00 sec)
Rows matched: 7 Changed: 3 Warnings: 0
mysql>
mysql> update ingredients set available = 'y'
-> where id in (1,3,7);
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3 Changed: 3 Warnings: 0
mysql>
mysql> select recipes.name from
-> (select recipe_id, available from
-> recipe_ingredient,
-> ingredients
-> where ingredient_id = ingredients.id
-> group by recipe_id, available) x, recipes
-> where recipes.id = x.recipe_id
-> group by x.recipe_id
-> having count(*) = 1
-> and max(x.available) = 'y';
+------+
| name |
+------+
| soup |
+------+
1 row in set (0.06 sec)
SELECT recipe_id
FROM [select recipe_id, count(*) as num_of_ingredients from recipe_ingredient group by recipe_id]. AS x, [select recipe_ingredient.recipe_id as recipe_id, count(*) as num_of_ingredients
from recipe_ingredient, ingredients_avail
where
recipe_ingredient.ingredient_id = ingredients_avail.ingredient_id
group by recipe_ingredient.recipe_id]. AS y
WHERE x.recipe_id = y.recipe_id and
x.num_of_ingredients = y.num_of_ingredients;
此外,这里的语法更为典型:
SELECT x.recipe_id
FROM (
SELECT recipe_id, count(*) as num_of_ingredients
FROM recipe_ingredients
GROUP BY recipe_id
) x, (
SELECT recipe_id, count(*) as num_of_ingredients
FROM recipe_ingredients
JOIN ingredients_avail
ON recipe_ingredients.ingredient_id = ingredients_avail.ingredient_id
GROUP BY recipe_id
) y
WHERE x.recipe_id = y.recipe_id AND x.num_of_ingredients = y.num_of_ingredients;
因此,你希望食谱中的所有成分都在“可用”成分列表中。试试[sql match all]标签或右边相关标题下的链接。这叫做@ypercube哇,太棒了。是的,我就是这么想的,但我一定是把我的逻辑搞砸了。谢谢你的精彩链接。这个问题有10多种方法可以达到这个目的。也进行了基准测试。更一般的答案是1,2,7,8(如果您的可用成分在表或列表中,并且您不想动态创建SQL查询)。对,最终这些将在表中。如果我有可用的成分1,3和7,这是否正确工作?也就是说,它应该返回汤,因为我可以用1和7来制作汤。@Frew,是的,当1、3和7可用时,它会返回“汤”。我在上面添加了结果。太棒了,谢谢;我会看看这对我是否有效,如果是的话,你会得到奖励:-)事实上,我在想如何将其转换为我的模式时遇到了很多困难;也就是说,ID列表或子查询,而不是可用内容的标志列。我能得到一些帮助吗?