Yar*_*rin 132 mysql sql greatest-n-per-group mysql-variables
以下是最简单的可能示例,但任何解决方案都应该能够扩展到需要的n个顶级结果:
根据下面的表格,使用人员,组和年龄列,您将如何获得每组中最老的2个人?(组内的关系不应该产生更多结果,但按字母顺序给出前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`
Run Code Online (Sandbox Code Playgroud)
我希望能够建立起来,但我不知道如何.
Tar*_*ryn 84
这是一种方法,使用UNION ALL(参见SQL Fiddle with Demo).这适用于两个组,如果您有两个以上的组,那么您需要指定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
)
Run Code Online (Sandbox Code Playgroud)
有多种方法可以执行此操作,请参阅此文章以确定适合您情况的最佳路径:
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;
Run Code Online (Sandbox Code Playgroud)
见演示
Mar*_*ers 62
在其他数据库中,您可以使用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
Run Code Online (Sandbox Code Playgroud)
看到它在线工作:sqlfiddle
编辑我刚注意到bluefeet发布了一个非常相似的答案:给他+1.然而,这个答案有两个小优点:
所以我会留在这里,以防它可以帮助某人.
snu*_*ffn 36
试试这个:
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
Run Code Online (Sandbox Code Playgroud)
小智 31
如何使用自我加入:
CREATE TABLE mytable (person, groupname, age);
INSERT INTO mytable VALUES('Bob',1,32);
INSERT INTO mytable VALUES('Jill',1,34);
INSERT INTO mytable VALUES('Shawn',1,42);
INSERT INTO mytable VALUES('Jake',2,29);
INSERT INTO mytable VALUES('Paul',2,36);
INSERT INTO mytable VALUES('Laura',2,39);
SELECT a.* FROM mytable AS a
LEFT JOIN mytable AS a2
ON a.groupname = a2.groupname AND a.age <= a2.age
GROUP BY a.person
HAVING COUNT(*) <= 2
ORDER BY a.groupname, a.age DESC;
Run Code Online (Sandbox Code Playgroud)
给我:
a.person a.groupname a.age
---------- ----------- ----------
Shawn 1 42
Jill 1 34
Laura 2 39
Paul 2 36
Run Code Online (Sandbox Code Playgroud)
Bill Karwin给每个类别选择前10条记录的答案给了我很大的启发
另外,我正在使用SQLite,但这应该适用于MySQL.
另一件事:在上面,为方便起见,我用group列替换了列groupname.
编辑:
关于OP关于缺失领带结果的评论的后续跟进,我在snuffin的回答中增加了显示所有关系.这意味着如果最后一个是tie,则可以返回超过2行,如下所示:
.headers on
.mode column
CREATE TABLE foo (person, groupname, age);
INSERT INTO foo VALUES('Paul',2,36);
INSERT INTO foo VALUES('Laura',2,39);
INSERT INTO foo VALUES('Joe',2,36);
INSERT INTO foo VALUES('Bob',1,32);
INSERT INTO foo VALUES('Jill',1,34);
INSERT INTO foo VALUES('Shawn',1,42);
INSERT INTO foo VALUES('Jake',2,29);
INSERT INTO foo VALUES('James',2,15);
INSERT INTO foo VALUES('Fred',1,12);
INSERT INTO foo VALUES('Chuck',3,112);
SELECT a.person, a.groupname, a.age
FROM foo AS a
WHERE a.age >= (SELECT MIN(b.age)
FROM foo AS b
WHERE (SELECT COUNT(*)
FROM foo AS c
WHERE c.groupname = b.groupname AND c.age >= b.age) <= 2
GROUP BY b.groupname)
ORDER BY a.groupname ASC, a.age DESC;
Run Code Online (Sandbox Code Playgroud)
给我:
person groupname age
---------- ---------- ----------
Shawn 1 42
Jill 1 34
Laura 2 39
Paul 2 36
Joe 2 36
Chuck 3 112
Run Code Online (Sandbox Code Playgroud)
Tra*_*ty3 10
看一下这个:
SELECT
p.Person,
p.`Group`,
p.Age
FROM
people p
INNER JOIN
(
SELECT MAX(Age) AS Age, `Group` FROM people GROUP BY `Group`
UNION
SELECT MAX(p3.Age) AS Age, p3.`Group` FROM people p3 INNER JOIN (SELECT MAX(Age) AS Age, `Group` FROM people GROUP BY `Group`) p4 ON p3.Age < p4.Age AND p3.`Group` = p4.`Group` GROUP BY `Group`
) p2 ON p.Age = p2.Age AND p.`Group` = p2.`Group`
ORDER BY
`Group`,
Age DESC,
Person;
Run Code Online (Sandbox Code Playgroud)
SQL小提琴:http://sqlfiddle.com/#!2/cdbb6/15
当你有足够的行时,Snuffin解决方案似乎执行起来很慢而且Mark Byers/Rick James和Bluefeet解决方案在我的环境(MySQL 5.6)上不起作用,因为在执行select之后应用order by,所以这里是一个变体Marc Byers/Rick James解决方案解决了这个问题(带有额外的叠加选择):
select person, groupname, age
from
(
select person, groupname, age,
(@rn:=if(@prev = groupname, @rn +1, 1)) as rownumb,
@prev:= groupname
from
(
select person, groupname, age
from persons
order by groupname , age desc, person
) as sortedlist
JOIN (select @prev:=NULL, @rn :=0) as vars
) as groupedlist
where rownumb<=2
order by groupname , age desc, person;
Run Code Online (Sandbox Code Playgroud)
我在具有5百万行的表上尝试了类似的查询,并在不到3秒的时间内返回结果
WITH cte_window AS (
SELECT movie_name,director_id,release_date,
ROW_NUMBER() OVER( PARTITION BY director_id ORDER BY release_date DESC) r
FROM movies
)
SELECT * FROM cte_window WHERE r <= <n>;
Run Code Online (Sandbox Code Playgroud)
上面的查询将返回每个导演的最新 n 部电影。
如果其他答案不够快,请尝试使用此代码:
SELECT
province, n, city, population
FROM
( SELECT @prev := '', @n := 0 ) init
JOIN
( SELECT @n := if(province != @prev, 1, @n + 1) AS n,
@prev := province,
province, city, population
FROM Canada
ORDER BY
province ASC,
population DESC
) x
WHERE n <= 3
ORDER BY province, n;
Run Code Online (Sandbox Code Playgroud)
输出:
+---------------------------+------+------------------+------------+
| province | n | city | population |
+---------------------------+------+------------------+------------+
| Alberta | 1 | Calgary | 968475 |
| Alberta | 2 | Edmonton | 822319 |
| Alberta | 3 | Red Deer | 73595 |
| British Columbia | 1 | Vancouver | 1837970 |
| British Columbia | 2 | Victoria | 289625 |
| British Columbia | 3 | Abbotsford | 151685 |
| Manitoba | 1 | ...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
143392 次 |
| 最近记录: |