【问题标题】:Getting `n` rows for each id in a result set MYSQL为结果集中的每个 id 获取 n 行 MYSQL
【发布时间】:2012-10-23 13:46:13
【问题描述】:

我有一个查询,它会像这样按降序返回结果。

  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;

我怎样才能做到这一点?

【问题讨论】:

  • 我想从一个有限制的子查询中获取 cmets 表,而不是直接连接。可能相关:stackoverflow.com/q/2856397/438971
  • 谢谢回复,但你能通过在查询中指定它来帮助我吗?
  • 您是否查看了答案中 cmets 中的链接? MySQL中的高级采样,有点迷惑:explainextended.com/2009/03/06/advanced-row-sampling
  • 我看了但没看懂。
  • 刚刚做了一个示例,使用我使用的数据库中的订单表来显示前 10 名客户的所有订单(按订单数量),以显示方法:SELECT o.`customer_id`, o.`order_id`, o.`total_price` FROM `orders` o JOIN (SELECT oo.`customer_id` FROM `orders` oo GROUP BY oo.`customer_id` ORDER BY COUNT(oo.`order_id`) DESC LIMIT 10) ooo ON o.`customer_id` = ooo.`customer_id`

标签: mysql greatest-n-per-group


【解决方案1】:

您必须使用子查询来具体化一个表,该表包含每个记录(评论)的每个组(按帖子)中的排名。然后,在外部查询中,您可以仅过滤那些排名在所需范围内的记录(例如,[1,5] 前 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

【讨论】:

  • rank comments on user's desired posts 你能解释一下这是什么意思吗? c1.*, IFNULL(COUNT(*),0) rank 这部分在做什么rank ????????
  • 您想选择前 N 个 cmets,因此我们需要对每个帖子上的 cmets 进行排名,然后将我们的结果限制为仅在排名区间 [1, 5] 内的那些 cmets。在该部分中,rank 是前面表达式结果的别名(列名)。
  • 当我运行您的查询时,它显示column rank cannot be null,您能解释一下IFNULL(COUNT(*),0) 是什么意思吗??
  • 我已经从我的查询中删除了IFNULL(),因为它是不必要的...请刷新。
  • 好的,所以您根据帖子为每个评论分配数字(排名),这意味着如果帖子 1 有 7 个 cmets,我会将它们从 1 到 7 排名,然后如果帖子 24 cmets 我现在将在上面的查询中将它们从 1 排到 4,我将使用像 comments.rank BETWEEN 1 AND 5 这样的 where 子句并从每个 postid 获取 5 个值?????
猜你喜欢
  • 2015-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-20
相关资源
最近更新 更多