以下是最简单的示例,尽管任何解决方案都应该能够扩展到需要多少n个top结果:
给定一个像下面这样的表格,有个人、团体和年龄列,你如何得到每组中最老的两个人?(组内的联系不应该产生更多的结果,而是按照字母顺序给出前2个)
+--------+-------+-----+ | Person | Group | Age | +--------+-------+-----+ | Bob | 1 | 32 | | Jill | 1 | 34 | | Shawn | 1 | 42 | | Jake | 2 | 29 | | Paul | 2 | 36 | | Laura | 2 | 39 | +--------+-------+-----+
期望结果集:
+--------+-------+-----+ | Shawn | 1 | 42 | | Jill | 1 | 34 | | Laura | 2 | 39 | | Paul | 2 | 36 | +--------+-------+-----+
注意:这个问题建立在前一个问题的基础上——为每组分组的SQL结果获取最大值的记录——用于从每个组中获取一个最上面的行,并从@Bohemian获得了一个非常好的MySQL特定答案:
select *
from (select * from mytable order by `Group`, Age desc, Person) x
group by `Group`
我很想能够以此为基础,尽管我不知道该怎么做。
这里有一种方法可以做到这一点,使用UNION-ALL
(参见SQLFiddle-with-Demo)。这适用于两个组,如果您有两个以上的组,则需要指定组
编号,并为每个组
添加查询:
(
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;
见演示
在其他数据库中,您可以使用行号
执行此操作。MySQL不支持行数
,但您可以使用变量来模拟它:
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
编辑我刚刚注意到蓝脚报上了一个非常相似的答案:1给他。然而,这个答案有两个小优点:
所以我会把它留在这里,以防它能帮助别人。
试试这个:
SELECT a.person, a.group, a.age FROM person AS a WHERE
(SELECT COUNT(*) FROM person AS b
WHERE b.group = a.group AND b.age >= a.age) <= 2
ORDER BY a.group ASC, a.age DESC
演示