简体   繁体   中英

Issue with count and group by to get inner join with count of 0

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.

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