views:

200

answers:

3

I'm trying to write a query that returns the user ID's of the top 10 users who gained the most points in the last 7 days on my web app.

I have three tables that, together, have the info I need.

  1. votingapi_votes table. It has a record for every up/down vote on a comment or node.
  2. node table. It can associate a node ID with a user ID so you can figure out who posted the story getting the votes.
  3. comments table, which does the same for comments.

I believe I need to write a query that selects every vote on a comment or node from the last week from the votingapi_vote table.

Here's the structure of that table:

  • vote_id
  • content_type
  • content_id
  • value
  • value_type
  • tag
  • uid
  • timestamp

So I'd SELECT rows of content_type "node" or "comment" with a Unix timestamp greater than time() - 684000.

Then it needs to

  1. group these votes by "content_id".

  2. Look up the respective "user_id" values for each content_id in the "node" and "comments" tables so we know who made the nodes and comments.

  3. Calculate how many points total each user_id gained from his nodes and comments.

  4. Sort these user_id's in reverse order and limits it to displaying only the first 10.

Phew. That seems like what I need to do. Now what does that actual query look like?

+2  A: 

Use:

SELECT x.*
  FROM (SELECT n.user_id,
               SUM(vav.value) 'total_votes'
          FROM NODE n
          JOIN VOTINGAPI_VOTES vav ON vav.content_id = n.nid
                                  AND vav.content_type = 'node'
         WHERE vav.timestamp > NOW() - 684000
      GROUP BY n.user_id
       UNION
       SELECT c.user_id,
              SUM(vav.value) 'total_votes'
         FROM COMMENTS c
         JOIN VOTINGAPI_VOTES vav ON vav.content_id = c.cid
                                 AND vav.content_type = 'comment' 
        WHERE vav.timestamp > NOW() - 684000
     GROUP BY c.user_id) x
ORDER BY x.total_votes DESC
   LIMIT 10
OMG Ponies
I think his `uid` refers to the voter id, not the id of the comment-owner
K Prime
A few notes:1. Line 4 should say content_type, I think, not content_id.2. the "uid" column doesn't tell you who posted the node/comment, but who voted for it. We need to go grab data from the "node" and "comments" tables to figure out who created each node/comment.Table structure of "node" table:nid uidTable structure of comments tablecid uidcid and nid should have equivalents over in the content_id column of the votingapi_votes table. matching content_id's of content_type "node" and maching content_id's of content_type "comment".That's where it gets confusing...
bflora
Rewrote based on feedback
OMG Ponies
I think we're really, really close. I'm getting an error: "Unknown column 'n.user_id' in 'group statement'"
bflora
Change the second `n.user_id` to `c.user_id`
K Prime
Works like a charm!
bflora
+3  A: 

Posting based on OMG Ponies' answer

SELECT x.user_id, SUM(x.total_votes)
    FROM (
        SELECT n.user_id, SUM(vav.value) AS total_votes
            FROM NODE n
            JOIN VOTINGAPI_VOTES vav 
                ON vav.content_id = n.nid
                AND vav.content_type = 'node'
            WHERE vav.timestamp > NOW() - 684000
            GROUP BY n.user_id
        UNION
        SELECT c.user_id, SUM(vav.value) AS total_votes
            FROM COMMENTS c
            JOIN VOTINGAPI_VOTES vav 
                ON vav.content_id = c.cid
                AND vav.content_type = 'comment' 
            WHERE vav.timestamp > NOW() - 684000
            GROUP BY c.user_id
    ) x
    GROUP BY 
        x.user_id
    ORDER BY 
        x.total_votes DESC
    LIMIT 10

The problem with the earlier code is that it returns 2 rows per user, 1 for comment, 1 for node. This code will do another SUM to aggregate it to just 1 number per user.

K Prime
Not sure I follow. They both appear to return the same results.
bflora
Ok. Now I'm seeing different results. This second answer does indeed SUM up the votes for nodes and comments. However, it's not listing them in proper descending order. The guy with the most points is currently listed #3 on the list that this query spits out.
bflora
Problem solved. had to sort by SUM(x.total_votes) DESC.
bflora
Ah.. missed that bit. Glad you solved it =)
K Prime
A: 

Can you just use the Views module? I'm pretty sure you can...

theunraveler
Views is slooooooow
bflora
Then you are not caching correctly, my friend.
theunraveler