在结果集MYSQL中为每个id获取`n`行

时间:2012-10-23 13:46:13

标签: mysql greatest-n-per-group

我有一个查询,按照这样的降序返回结果。

  comment     postid      name      userid    tempid
  ----------------------------------------------------- 
    c1          199        User1      123321    1
    c2          199        User1      123321    2
    c3          199        User1      123321    3
    c4          199        User1      123321    4
    c5          199        User1      123321    5
    c6          199        User1      123321    6
    c7          198        User1      123321    7
    c8          198        User1      123321    8
    c9          198        User1      123321    9
    c10         197        User1      123321    10
    c11         197        User1      123321    11
    c12         197        User1      123321    12
    c13         197        User1      123321    13
    c14         197        User1      123321    13
    c15         197        User1      123321    13
    c16         197        User1      123321    13

现在我想为每个postid选择前5个记录。结果应该是

  comment     postid      name      userid    tempid
  ----------------------------------------------------- 
    c1          199        User1      123321    1
    c2          199        User1      123321    2
    c3          199        User1      123321    3
    c4          199        User1      123321    4
    c5          199        User1      123321    5
    c7          198        User1      123321    7
    c8          198        User1      123321    8
    c9          198        User1      123321    9
    c10         197        User1      123321    10
    c11         197        User1      123321    11
    c12         197        User1      123321    12
    c13         197        User1      123321    13
    c14         197        User1      123321    13

这是我的疑问。

 DECLARE rangee INT;
 DECLARE uid BIGINT;

 SET @rangee = plimitRange * 10; 
 SET @uid    = puserid;

PREPARE STMT FROM
'
SELECT comments.comment,comments.postid,user.name,comments.userid,comments.tempid 
FROM
user
INNER JOIN comments ON user.userid=comments.userid
INNER JOIN posts ON posts.postID = comments.postid
 WHERE 
comments.postid <=  
(SELECT MAX(postid) FROM
 (
  SELECT wall.postid FROM wall,posts WHERE  
  wall.postid = posts.postid AND posts.userid=?
  ORDER BY wall.postid DESC LIMIT 10 OFFSET ?
 )sq1
)

AND
comments.postid >= 
(SELECT MIN(postid) FROM
 (
   SELECT wall.postid FROM wall,posts WHERE
   wall.postid = posts.postid AND posts.userid=?
   ORDER BY wall.postid DESC LIMIT 10 OFFSET ?
  )sq2
)

 AND
 posts.userid = ?
 ORDER BY comments.postid DESC,comments.tempid DESC;
'; 
EXECUTE STMT USING @uid,@rangee,@uid,@rangee,@uid;
DEALLOCATE PREPARE STMT;

我该如何做到这一点?

1 个答案:

答案 0 :(得分:3)

您必须使用子查询来实现一个表,该表包含每个记录(注释)的每个组(按帖子)中的排名。然后,在外部查询中,您只能过滤那些排名在所需范围内的记录(例如前5名[1,5]):

-- select top 5 comments of each of the user's desired posts
SELECT   comments.comment,
         comments.postid,
         user.name,
         comments.userid,
         comments.tempid
FROM     user JOIN (
           -- rank comments on user's desired posts by grouping a self-join
           -- use index (postid, tempid) for performance
           SELECT      c1.*, COUNT(*) rank
           FROM        (
                         -- select user's posts within desired range
                         SELECT postid
                         FROM   (
                                  -- rank user's posts by grouping a self-join
                                  -- use index (userid, postid) for performance
                                  SELECT      p1.postid, COUNT(*) rank
                                  FROM        posts p1
                                    LEFT JOIN posts p2
                                           ON p1.userid = p2.userid
                                          AND p1.postid < p2.postid
                                  WHERE       p1.userid = @uid
                                  GROUP BY    p1.postid
                                ) ranked_posts
                         WHERE  rank BETWEEN @rangee + 1 AND @rangee + 10
                       ) interesting_posts
                  JOIN comments c1 USING (postid)
             LEFT JOIN comments c2
                    ON c1.postid = c2.postid
                   AND c1.tempid < c2.tempid
           GROUP BY c1.postid
         ) comments USING (userid)
WHERE    comments.rank BETWEEN 1 AND 5
ORDER BY postid DESC, tempid DESC