搜索

首页  >  问答  >  正文

抓取每个分组结果中的前n条记录

<p>以下是最简单的可能示例,但任何解决方案都应能够扩展到所需的n个顶部结果:</p> <p>给定如下表格,其中包含人员、组和年龄列,如何获取每个组中年龄最大的2个人?(组内的并列情况不应产生更多结果,而是按字母顺序给出前2个)</p> <pre> +--------+-------+-----+ | Person | Group | Age | +--------+-------+-----+ | Bob | 1 | 32 | | Jill | 1 | 34 | | Shawn | 1 | 42 | | Jake | 2 | 29 | | Paul | 2 | 36 | | Laura | 2 | 39 | +--------+-------+-----+ </pre> <p>期望的结果集:</p> <pre> +--------+-------+-----+ | Shawn | 1 | 42 | | Jill | 1 | 34 | | Laura | 2 | 39 | | Paul | 2 | 36 | +--------+-------+-----+ </pre> <hr> <p><strong>注意:</strong>这个问题是基于之前的一个问题——获取每个组的最大值的记录的SQL结果 - 用于获取每个组的单个顶部行,并且从@Bohemian获得了一个很好的MySQL特定的答案:</p> <pre class="brush:php;toolbar:false;">select * from (select * from mytable order by `Group`, Age desc, Person) x group by `Group`</pre> <p>很想能够在此基础上继续构建,但我看不出如何做到。</p>
P粉785957729P粉785957729495 天前465

全部回复(2)我来回复

  • P粉340264283

    P粉3402642832023-08-22 19:25:52

    在其他数据库中,您可以使用ROW_NUMBER来实现此功能。MySQL不支持ROW_NUMBER,但您可以使用变量来模拟它:

    SELECT
        person,
        groupname,
        age
    FROM
    (
        SELECT
            person,
            groupname,
            age,
            @rn := IF(@prev = groupname, @rn + 1, 1) AS rn,
            @prev := groupname
        FROM mytable
        JOIN (SELECT @prev := NULL, @rn := 0) AS vars
        ORDER BY groupname, age DESC, person
    ) AS T1
    WHERE rn <= 2

    在线演示: sqlfiddle


    编辑 我刚刚注意到bluefeet发布了一个非常相似的答案:给他+1。但是这个答案有两个小优点:

    1. 这是一个单一查询。变量在SELECT语句内部初始化。
    2. 它处理了问题中描述的并列情况(按名称的字母顺序)。

    因此,我将保留它,以防它能帮助到某人。

    回复
    0
  • P粉404539732

    P粉4045397322023-08-22 13:19:02

    以下是一种方法,使用UNION ALL(请参见带有演示的SQL Fiddle)。这适用于两个组,如果你有多个组,则需要指定group编号并为每个group添加查询:

    (
      select *
      from mytable 
      where `group` = 1
      order by age desc
      LIMIT 2
    )
    UNION ALL
    (
      select *
      from mytable 
      where `group` = 2
      order by age desc
      LIMIT 2
    )

    有多种方法可以实现这个目标,请参考本文以确定适合您情况的最佳方法:

    http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/

    编辑:

    这也可能适用于您,它为每条记录生成一个行号。使用上面链接中的示例,它将仅返回行号小于或等于2的记录:

    select person, `group`, age
    from 
    (
       select person, `group`, age,
          (@num:=if(@group = `group`, @num +1, if(@group := `group`, 1, 1))) row_number 
      from test t
      CROSS JOIN (select @num:=0, @group:=null) c
      order by `Group`, Age desc, person
    ) as x 
    where x.row_number <= 2;

    请参见演示

    回复
    0
  • 取消回复