3

I need a way for page moderators to view the members of their page ordered by the total number of posts the user has on that particular page. The posts are stored in different tables such as polls, downloads, wiki, etc (like 15 tables). Each of those have the structure of id, user_id, page_id, title, content, etc etc. The table that lists all the users of a page is called 'favorites'. The structure of that is simply id, user_id, page_id, date.

I currently have a query that unions all of the "content tables" together for a specific user to display ALL of their posts across the site regard of what page it is on, I could easily make it specific to each page using WHERE page_id = $page_id). I tried using that code to do what I'm trying to do in the moderator area. As I mentioned, in the moderator area I need to sort the list of users by their total posts count DESC.

I have this code but it is not working.

$getfans = mysql_query("SELECT DISTINCT user_id, ((SELECT id FROM wiki WHERE wiki.page_id = $page_id AND wiki.user_id = favorites.user_id)
UNION ALL
(SELECT id FROM downloads WHERE downloads.page_id = $page_id AND downloads.user_id = favorites.user_id)
UNION ALL
(SELECT id FROM polls WHERE polls.page_id = $page_id AND polls.user_id = favorites.user_id)) AS posts 
FROM favorites WHERE favorites.page_id = $page_id AND favorites.status = 0 ORDER BY posts DESC", $conn);

I tried other methods that also did not work but this one made the most logical sense to me so it's the only one I'm going to display

Please help. Thanks.

Additionally...

This was perhaps a step in the right direction

$getfans = mysql_query("SELECT DISTINCT user_id, (SELECT COUNT(id) FROM polls WHERE page_id = $page_id AND user_id = favorites.user_id) AS posts FROM favorites WHERE favorites.page_id = $page_id AND favorites.status = 0 ORDER BY posts DESC", $conn);

When I echo'ed $posts it gave me the correct count for the user's polls for that page.

HOWEVER when I tried to do more than one table it only returned one user.

Example:

$getfans = mysql_query("SELECT DISTINCT user_id, SUM((SELECT COUNT(id) FROM polls WHERE page_id = $page_id AND user_id = favorites.user_id)+(SELECT COUNT(id) FROM wiki WHERE page_id = $page_id AND user_id = favorites.user_id)) AS posts FROM favorites WHERE favorites.page_id = $page_id AND favorites.status = 0 ORDER BY posts DESC", $conn);

I FOUND THE SOLUTION
if curious, just read my post below.

pad
  • 41,040
  • 7
  • 92
  • 166
bowlerae
  • 924
  • 1
  • 14
  • 37
  • Are you summing up how many rows are in each table for each user? – Tom Cerul Dec 16 '11 at 19:39
  • Yes. And I've done various methods including COUNT(*) and * but still none worked. The entire union block by itself works when I'm just trying to display all of the posts for a user but not when I'm trying to display all users and then order by the posts. – bowlerae Dec 16 '11 at 19:48

3 Answers3

1

Use left joins!

SELECT 
    f.user_id, 
    COUNT(w.user_id) + COUNT(d.user_id) + COUNT(p.user_id) as PageCount
FROM 
    favorites f
    left join wiki w on
        f.page_id = w.page_id
        and f.user_id = w.user_id
    left join downloads d on
        f.page_id = d.page_id
        and f.user_id = d.user_id
    left join polls p on
        f.page_id = p.page_id
        and f.user_id = p.user_id
WHERE 
    f.page_id = $page_id 
    AND f.status = 0
GROUP BY
    f.user_id
ORDER BY PageCount DESC

If you'd like to stick with the union approach:

select
    f.user_id,
    count(x.user_id) as PageCount
from
    favorites f
    inner join (
        select user_id, page_id from wiki
        union all
        select user_id, page_id from downloads
        union all
        select user_id, page_id from polls
        union all
        select user_id, page_id from videos
    ) x on
       f.user_id = x.user_id
       and f.page_id = x.page_id
WHERE 
    f.page_id = $page_id 
    AND f.status = 0
group by
    f.user_id
ORDER BY PageCount DESC

You want to use a group by for aggregates, and the count function will ignore any nulls that you run into, so it will only count positive matches.

Eric
  • 92,005
  • 12
  • 114
  • 115
  • ummm I'm not sure if that's it going to be pleasant seeing as the tables I have are not just the three in my example (polls, wiki and downloads) but ALSO..videos, photos, walkthrough, wiki, reviews, articles, news, disputes, forums_posts, quotes, quizzes..and probably some others I'm missing. I don't understand if I can count all of these using one large union for the user to see a long list of all of their posts, why can't I use that same count to order their posts by? – bowlerae Dec 16 '11 at 20:43
  • Added the union approach. Don't know on MySQL, but SQL Server usually optimizes those predicates so you aren't pulling lots of stuff back. At any rate, you won't actually *see* the tables in the left join instance, you'll just be using them to filter your query. The only thing you'll see are the columns that you pull back in the `select` portion of the clause. – Eric Dec 16 '11 at 20:53
  • Also, I just tried your code but it didn't work. I also changed PageCount to posts to see if that was the problem but that didn't work either. – bowlerae Dec 16 '11 at 20:56
  • What's "didn't work" mean? What results were you expecting to see but didn't? Or did you receive an error? Which code did you try--the first one or the second one? – Eric Dec 16 '11 at 20:59
  • I was originally talking about the first one but I just tried the second one with the union and it still didn't work. Didn't work as in the table is blank (I'm displaying the users in a stats table...it comes up empty). Returns 0 results. – bowlerae Dec 16 '11 at 21:05
  • D'oh, had an errant `order by` clause--I forget MySQL is very liberal with `group by`. Edited both of them. Try that. – Eric Dec 16 '11 at 21:08
  • 1
    AHHHHHHHH :) only one change. I had to change INNER JOIN to LEFT JOIN because I needed it to display ALL users for the page even those with 0 posts and before (with the inner join) it was only display users that had rows in the other tables. THANKSSSSSSSS – bowlerae Dec 16 '11 at 21:12
  • I guess I didn't look at my page fully when I thought it was working. Scratch my Ahhhh, the code is not working correctly. I display the results of the stats table with the number of posts for each user and the number of posts for them is inflated. It is saying the top user has 72 posts for the page when the entire page only has 52 posts for all of the different tables/modules and all of the different users combined. – bowlerae Dec 17 '11 at 00:05
1

I FOUND THE SOLUTION. I thought I had this earlier but I guess I was off by the slightest bit. Thanks everyone who participated.

$getfans = mysql_query("SELECT DISTINCT user_id,
(SELECT COUNT(id) FROM wiki WHERE page_id = $page_id AND user_id = favorites.user_id) + 
(SELECT COUNT(id) FROM downloads WHERE page_id = $page_id AND user_id = favorites.user_id) + 
(SELECT COUNT(id) FROM polls WHERE page_id = $page_id AND user_id = favorites.user_id)  
AS posts FROM favorites
WHERE favorites.page_id = $page_id
AND favorites.status = 0
ORDER BY posts DESC", $conn);

just keep doing the subquery with the + at the end for each new table. Perhaps not the most concise code but it works.

This works. I can't accept it as an answer for two days :(

bowlerae
  • 924
  • 1
  • 14
  • 37
-1

This is my favorite SQL query, for one table,

Select Distinct user_id, Count(user_id) as C from yourtable group by user_id 

will show you each person's user_id and the number of rows they have in that table. Combining a bunch of these results should be straightforward.

BTW, if all the tables have the same structure, why not have them all be in the same table? You could add a column indicating what type of item the record applies to.

Tom Cerul
  • 1,773
  • 2
  • 13
  • 27
  • It would be extremely messy that way because the structures are not the exact same. – bowlerae Dec 16 '11 at 20:03
  • ...and I'm not sure how what you wrote is going to apply to the 3 tables I gave in the example. Could you please explain further? Actually using my tables in your example? – bowlerae Dec 16 '11 at 20:04
  • 1
    I downvoted you for two reasons: (1) You're using an unnecessary `distinct` when you have a `group by`, and (2) you only showed a generic aggregation instead of helping the user solve his or her problem. – Eric Dec 16 '11 at 20:37
  • The distinct was probably my fault since I've just been trying everything (sort of pulling at straws here) and sometimes when I move on to my next attempt, some things linger in my query that should not be there until I realize it and take it out and try again. He just copy and pasted. As for the not helping, I agree. – bowlerae Dec 16 '11 at 20:42
  • ya know, Eric, I've been using that query for years. I'm not sure that the distinct is needed or not anymore. – Tom Cerul Dec 16 '11 at 20:59