Reputation: 23
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.
Upvotes: 2
Views: 102
Reputation: 1269803
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.
Upvotes: 2
Reputation: 16690
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.
Upvotes: 0
Reputation: 5243
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
Upvotes: 0
Reputation: 29051
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;
Upvotes: 2
Reputation: 38130
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
Upvotes: 0