I have the following query:
SELECT s.username FROM `instagram_shop` s
INNER JOIN `instagram_shop_picture` p ON
s.id = p.shop_id
WHERE COUNT(p.id) = 0
GROUP BY p.id
;
I essentially wanted to find all shops that doesn't have any pictures yet. I wanted to get the username of the shop. However the above query gives me #1111 - Invalid use of group function
why is this?
Here's what the instagram_shop looks like:
and here's the instagram_shop_picture:
WHERE
filters are executed against the data before aggregation occurs (aggregation being a GROUP BY or SUM() or AVG(), for instance). If you need to filter your results after aggregation you will need to use HAVING
SELECT s.username, count(p.id)
FROM `instagram_shop` s
LEFT JOIN `instagram_shop_picture` p ON
s.id = p.shop_id
GROUP BY s.username
HAVING COUNT(p.id) = 0;
It's important to note that HAVING
can be an expensive procedure since the database has to return and aggregate all of your results before it is used. So if your returned results are HUGE, HAVING
is going to churn for a while.
ADDED: As folks have pointed out, because of your schema, you need to use a LEFT JOIN here. Using an INNER JOIN causes you to drop records from your result where there are no pictures. Once that's done there will be no records before OR after aggregation where the count(p.id) = 0. So you get nothing back.
Seeing your schema you could also use:
SELECT s.username
FROM `instagram_shop` s
LEFT JOIN (SELECT shop_id, count(id) as countOfPictures FROM `instagram_shop_picture`) p ON
s.id = p.shop_id
WHERE p.countOfPictures IS NULL
This may actually reduce runtime since it involves aggregating on a smaller result from a single table (where the index can be taken into consideration by the DB). The derived table adds back some overhead, but overall you'll probably come out ahead.
You have two things to correct here.
HAVING
for conditions related to Aggregate functions
Where
is for the filter to be applied before the data gets aggregated using Count, Min, Max, Sum, etc.
Having
is to be used after the aggregation is done, and only on aggregation functions.
Use a LEFT OUTER JOIN
Or EXISTS
When you use an Inner Join
, you will only get rows from instagram_shop, and instagram_shop_picture. To get rows that do not exist in instagram_shop_picture, you can use an OUTER JOIN
, or use an EXISTS
SELECT s.username
FROM instagram_shop s
LEFT OUTER JOIN instagram_shop_picture p
ON s.id = p.shop_id
GROUP BY p.id
HAVING COUNT(p.id) = 0
OR
SELECT s.username
FROM instagram_shop s
Where Not Exists
(
Select 1
From instagram_shop_picture p
Where s.id = p.shop_id
)
Try following
Select *
From `instagram_shop` s Left Join `instagram_shop_picture` p On s.id = p.shop_id
Where p.shop_id is null
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.