抓取每个分组结果中的前n条记录
P粉785957729
P粉785957729 2023-08-21 19:55:22
0
2
460
<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粉785957729
P粉785957729

全部回复(2)
P粉340264283

在其他数据库中,您可以使用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. 它处理了问题中描述的并列情况(按名称的字母顺序)。

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

P粉404539732

以下是一种方法,使用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;

请参见演示

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板