简体   繁体   中英

MySQL 'AND' query not working as expected

I've got 3 tables i'm currently working on. Recipe, Ingredient and recipeIng. It's the classic many to many situation, with recipeIng there to solve that problem.

However, i'm having trouble getting a what I assumed to be, a fairly simple 'AND' query. What i'm trying to achieve is searching for multiple ingredients at once. For instance:

SELECT r.recipeTitle AS recipe
FROM Recipe r
WHERE recipeID IN(
    SELECT r.recipeID
    FROM recipeIng il, Ingredient i
    WHERE (il.ingredientID = i.ingredientID)
    AND (il.recipeID = r.recipeID)
    AND (i.ING LIKE '%cheese%' AND i.ING LIKE '%salmon%')

);

While the query runs, it outputs nothing. I can't seem to see what i'm doing wrong here. Any help would be really appreciated.

Thanks.

So basically you want the recipes that includes any of the ingredients you're querying on. This can be performed using simple straight joins:

SELECT DISTINCT(r.recipeTitle) AS recipe
FROM Ingredient i
INNER JOIN recipeIng il ON il.ingredientID = i.ingredientID
INNER JOIN Recipe r ON r.recipeID = il.recipeID
WHERE i.ING LIKE '%cheese%' OR i.ING LIKE '%salmon%'

The DISTINCT() makes sure that you're not seeing the same recipe twice in case it contains both ingredients.

If both ingredients must be present in the recipes, you must use AND instead of OR .

First of all, your query can be massively simplified as you do not need the outer query. The following is exactly the same:

SELECT r.recipeTitle AS recipe
FROM recipeIng il, Ingredient i, Recipe r
WHERE (il.ingredientID = i.ingredientID)
AND (il.recipeID = r.recipeID)
AND (i.ING LIKE '%cheese%' AND i.ING LIKE '%salmon%')

Secondly, you don't need all those brackets.

SELECT r.recipeTitle AS recipe
FROM recipeIng il, Ingredient i, Recipe r
WHERE il.ingredientID = i.ingredientID
AND   il.recipeID = r.recipeID
AND   i.ING LIKE '%cheese%' 
AND i.ING LIKE '%salmon%'

Thirdly, you should INNER JOIN your tables to make the relationship between them clearer:

SELECT r.recipeTitle AS recipe
FROM recipeIng il JOIN 
     Ingredient i ON  il.ingredientID = i.ingredientID JOIN
     Recipe r ON il.recipeID = r.recipeID
WHERE i.ING LIKE '%cheese%' 
AND   i.ING LIKE '%salmon%'

At this point, the issue should be clear - there are 2 likely possibilities, and 2 is more likely than 1.

1) Your ING field stores all the ingredients for a recipe in a single field. If this is the case then you do not have a recipe who's ingredients call for both Cheese and Salmon.

2) Your ING field only stores 1 ingredient per row. However, you are asking for a single row which contains both Cheese and Salmon . This is not your intention, and the query is therefore wrong.

-- SELECT ALL RECIPES USING CHEESE *OR* SALMON
SELECT r.recipeTitle AS recipe
FROM recipeIng il JOIN 
     Ingredient i ON  il.ingredientID = i.ingredientID JOIN
     Recipe r ON il.recipeID = r.recipeID
WHERE i.ING LIKE '%cheese%' 
AND   i.ING LIKE '%salmon%'

-- SELECT ALL RECIPES USING CHEESE *AND* SALMON
SELECT r.recipeTitle AS recipe
FROM recipeIng il JOIN 
     Ingredient iCheese 
         ON  il.ingredientID = i.ingredientID 
         AND i.ING LIKE '%cheese%'  JOIN
     Ingredient iSalmon 
         ON  il.ingredientID = i.ingredientID 
         AND i.ING LIKE '%salmon%'  JOIN 
     Recipe r ON il.recipeID = r.recipeID

Please note the above are for example only - without knowing your schema, these are merely hints and suggestions :)

Use i.ING LIKE '%cheese%' OR i.ING LIKE '%salmon%' instead of AND , and add GROUP BY r.recipeID with HAVING COUNT(DISTINCT i.ING ) = 2 to ensure that the selected r.recipeID have both ING :

SELECT r.recipeTitle AS recipe
FROM Recipe r
WHERE recipeID IN(
    SELECT r.recipeID
    FROM recipeIng il
    INNER JOIN Ingredient i ON il.ingredientID = i.ingredientID 
    WHERE il.recipeID = r.recipeID
      AND (i.ING LIKE '%cheese%' OR i.ING LIKE '%salmon%')
    GROUP BY r.recipeID
    HAVING COUNT(DISTINCT i.ING ) = 2
);

SQL Fiddle Demo

So if the r.recipeID have only one of them only, then the COUNT(DISTINCT i.ING ) won't be equal to 2 and there for it will be eliminated.

The HAVING COUNT(DISTINCT i.ING ) = 2 will give you those recipes that has exactly the two tags cheese and salmon only no more ingredients, if you are looking for those recipes that has at least both two ingredients, use `HAVING COUNT(DISTINCT i.ING ) >= 2 .

This is assuming that ingredients are entered in the field ING as a one value per row.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM