I have is a users table, a posts table, a private table, and a user_stats table:
users
user_id | user_name
--------------------
1 | tony
2 | steph
3 | lizzy
4 | adam
posts
post_id user_id sugg_by private (0 is public, 1 is private to authorized users)
-----------------------------------------------------
1 1 2 0
2 2 2 1
3 2 2 1
4 2 4 1
5 2 2 1
6 2 3 0
private
private_id post_id authorized_user_id
-----------------------------------------------
1 2 4
2 2 3
3 4 4
4 5 1
5 5 3
user_stats
user_id orig_posts_count(user_id=sugg_by in posts) sugg_posts_count(user_id<>sugg_by in posts)
-----------------------------------------------------------------------------------------------------
1 0 1
2 3 2
3 0 0
4 0 0
The problem I’m having is in this query. In this example ‘4’ is the $logged_in_id adam, and ‘2’ is the user_id of the posts we are counting for steph. If steph is logged_in, the COUNT will not run and we will give ‘posterview’, this works. Back to any other logged in user or anyone logged out and the issue begins. So for adam ‘4’:
SELECT u.user_id, us.orig_posts_count, us.sugg_posts_count,
IF(us.user_id='4', 'posterview',
COUNT(case when ISNULL(pv.post_id) AND p.private='1' AND p.user_id='2' AND p.sugg_by='2' then null else 1 end)
) as display_orig_posts_count,
IF(us.user_id='4', 'posterview',
COUNT(case when ISNULL(pv.post_id) AND p.private='1' AND p.user_id='2' AND p.sugg_by<>'2' then null else 1 end)
) as display_sugg_posts_count
FROM users u
JOIN user_stats us ON u.user_id=us.user_id
JOIN posts p ON p.user_id=us.user_id
LEFT JOIN private pv on pv.post_id = p.post_id AND pv.authorized_user_id='4'
WHERE u.user_id='2' LIMIT 1
The output should be:
user_id orig_posts_count sugg_posts_count display_orig_posts_count display_sugg_posts_count
2 3 2 1 2
It however outputs as:
user_id orig_posts_count sugg_posts_count display_orig_posts_count display_sugg_posts_count
2 3 2 3 5
I believe the reason for this is in the JOIN posts p ON p.user_id=us.user_id
If I turn it into JOIN posts p ON p.user_id=us.user_id AND p.sugg_by='2' (which matches the first COUNT for display_orig_posts_count), then the display_orig_posts_count is 1 which is correct, but display_sugg_posts_count is incorrect at 3. I get the correct display_orig_posts_count and incorrect display_sugg_posts_count. Outputs as:
user_id orig_posts_count sugg_posts_count display_orig_posts_count display_sugg_posts_count
2 3 2 1 3
If I turn it into JOIN posts p ON p.user_id=us.user_id AND p.sugg_by<>'2' (which matches the second COUNT for display_sugg_posts_count), then the display_orig_posts_count is 2 which is incorrect, but display_sugg_posts_count is correct at 2. Outputs as:
user_id orig_posts_count sugg_posts_count display_orig_posts_count display_sugg_posts_count
2 3 2 2 2
Basically, a logged in user if steph should return ‘posterview’, but any other user that uses COUNT should only see posts that are public (private 0), or (private 1) only if they are a part of it, and then count based on the condition in the COUNT clause to get the correct output as stated. I’ve been stuck on this for hours. Any idea how to get the query to work correctly?
Note: Fiddles are included for each example output.
Change your query to this:
DETAILED EXPLANATION
In your first query, the following posts are being counted (with reasons):
In your second query, the following posts are being counted (with reasons):
In your third query, the following posts are being counted (with reasons):
What do we want to be counted:
So let’s clean this up:
Strip out
p.user_id='2'from `CASE1 statementsThis is always true anyway, because you’re limiting posts to only those posts with
user_id='2'by virtue of yourJOINstatements.Use affirmative checks
In the case of
display_orig_posts_count, we want certain things. Rather than trying to filter out the things we don’t want, let’s explicitly look for the things we do want:In the case of
display_sugg_posts_count, let’s again look for those things explicitly:Use
GROUP BYwhen using aggregation functionsYou shouldn’t need
LIMIT 1, either, if you’re properly grouping aggregated functions. Only one row should ever be returned for each user.