2

I am having trouble writing the following query in MySQL. I have a table called pizz0r_pizza_ingredients which looks something like this:

| id | pizza_id | ingredient | amount | measure |
+----+----------+------------+--------+---------+
| 6  |    1     |    15      |   3    |    4    |
|178 |    17    |    1       |   160  |    1    |
| 3  |    1     |    20      |   3    |    4    |

I want to search for pizzas where the ingredients have specific requirements such as the following:

SELECT `pizza_id` 
FROM `pizz0r_pizza_ingredients` 
WHERE `ingredient` = 15 AND `ingredient` != 20 
GROUP BY `pizza_id`

I am trying to get entries where ingredient is equal to 15, but ignores that pizza_id if it also has ingredient 20.

The current result is 1, but in this example nothing should be returned.

AdamMc331
  • 16,492
  • 10
  • 71
  • 133

5 Answers5

2

Try this:

SELECT P1.pizza_id 
FROM pizz0r_pizza_ingredients P1 
LEFT OUTER JOIN pizz0r_pizza_ingredients P2 ON P1.pizza_id = P2.pizza_id AND P2.ingredient IN (20, 21)
WHERE P1.ingredient = 15 AND P2.id IS NULL
GROUP bY P1.pizza_id;
Saharsh Shah
  • 28,687
  • 8
  • 48
  • 83
2

I like to handle these problems using group by and having:

SELECT `pizza_id` 
FROM `pizz0r_pizza_ingredients` 
GROUP BY `pizza_id`
HAVING SUM(ingredient = 15) > 0 AND
       SUM(ingredient = 20) = 0;

You can add as many new requirements as you like. The SUM() expression counts the number of ingredients of a certain type. The > 0 means that there is at least one on the pizza. The = 0 means that there are none.

Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
0

You need to combine the two sets of data - everything you might want, and then exclude those that intersect your unwanted ingredients, so something like:

SELECT DISTINCT
            wanted.pizza_id

FROM        pizz0r_pizza_ingredients wanted 

LEFT JOIN   pizz0r_pizza_ingredients dontwant
    ON      wanted.pizza_id = dontwant.pizza_id
    AND     dontwant.ingredient IN ( 20, 21 )

WHERE       wanted.ingredient IN ( 15 ) -- You could have multiples, if you wanted ham OR chicken, for example
    AND     dontwant.pizza_id IS NULL -- No bad ingredients
Rowland Shaw
  • 37,700
  • 14
  • 97
  • 166
0

EDIT: Your question was unclear earlier. If you wanted to exclude pizzas with ingredient 20, you can use the below:

select pizzaid from pizz0r_pizza_ingredients where ingredient = 15
EXCEPT
select pizzaid from pizz0r_pizza_ingredients where ingredient != 20

NOTE: EXCEPT is generally faster than join or not in

SouravA
  • 5,147
  • 2
  • 24
  • 49
  • Thanks, but thats not quite what i wanted. I dont want This OR that i want both requirements on one Pizza_id. Its kinda hard for me to describe. – Stephan Wahlen Dec 29 '14 at 14:35
  • Im gettin mysql error #1064 with this one, i guess my version does not recognize EXCEPT. Thanks anyway, i got a working suggestion above. – Stephan Wahlen Dec 29 '14 at 14:44
  • I don't think MySQL supports EXCEPT at all. – AdamMc331 Dec 29 '14 at 14:45
  • 1
    @StephanWahlen, I was wrong, MySQL doesn't support `EXCEPT`. Thanks @McAdam331 for pointing that out. Its a shame though. – SouravA Dec 29 '14 at 14:50
0

One option you have is to use subqueries for this. To understand this best, I would first separate the two queries and then combine them.

The first one will pull all pizza_id that have ingredient 15:

SELECT DISTINCT pizza_id
FROM myTable
WHERE ingredient = 15;

Then, you can write another one that searches for pizza_id where ingredient is equal to 20:

SELECT DISTINCT pizza_id
FROM myTable
WHERE ingredient = 20;

Last, you can combine the two by using the NOT IN clause. In other words, you can select all pizza_id that meet the first condition, where the id is NOT IN the pizza_ids that meet the second condition:

SELECT DISTINCT pizza_id
FROM myTable
WHERE ingredient = 15 AND pizza_id NOT IN(
  SELECT DISTINCT pizza_id
  FROM myTable
  WHERE ingredient = 20);

EDIT

Here is an SQL Fiddle.

EDIT 2

This is a subject known as relational division. There is another example similar to this here.

Community
  • 1
  • 1
AdamMc331
  • 16,492
  • 10
  • 71
  • 133