There are a number of ways this can be solved, but the most intuitive option (to me) would be to use window functions, since each column in your desired output is rather simple to calculate on its own. Assuming that your user and post tables are named user
and post
:
SELECT `category`, `Count (At least 1 post)`, `users_per_category` - `Count (At least 1 post)` AS `Count (No post)`FROM ( SELECT `category`, COUNT(DISTINCT `user_id`) AS `Count (At least 1 post)` FROM `post` JOIN `user` USING (`user_id`) GROUP BY `category`) AS `withpost` JOIN ( SELECT `category`, COUNT(DISTINCT `user_id`) AS `users_per_category` FROM `user` GROUP BY `category`) AS `totals` USING (`category`)
The first window function joins the user and the post tables to figure out how many users per category have made posts (you prevent multiple posts by one user from counting multiple times by using DISTINCT
).
The second window function figures out how many users there are in each category.
The select statement that brings it together calculates out the "no post" result by looking at the difference between the number of users per category with the number of users who have made posts.