我有一些格式如下:
Lane Series
1 680
1 685
1 688
2 666
2 425
2 775
...
而且我想要获得每个泳道最高的n系列(假设这个例子让我们说2个,但它可能会比这更多)
所以输出应该是:
Lane Series
1 688
1 685
2 775
2 666
获得每个泳道的最高系列很容易,但我似乎无法找到获得最高2个结果的方法。
我使用带有GROUP BY的MAX聚合函数来获取MAX,但是没有像SQL Server中那样的“TOP N”函数,并且使用ORDER BY ... LIMIT仅返回总体上最高的N个结果,而不是每个通道。
由于我使用JAVA应用程序,我编码自己查询数据库并选择N是什么,我可以做一个循环并使用LIMIT并遍历每个通道,每次都进行不同的查询,但我想学习如何用MySQL做到这一点。
答案 0 :(得分:5)
请参阅我的其他答案,仅针对MySQL,但非常快,解决方案。
此解决方案允许您为每个通道指定任意数量的顶行,并且不使用任何MySQL“时髦”语法 - 它应该在大多数数据库上运行。
select lane, series
from lane_series ls
group by lane, series
having (
select count(*)
from lane_series
where lane = ls.lane
and series > ls.series) < 2 -- Here's where you specify the number of top rows
order by lane, series desc;
测试输出:
create table lane_series (lane int, series int);
insert into lane_series values
(1, 680),
(1, 685),
(1, 688),
(2, 666),
(2, 425),
(2, 775);
select lane, series
from lane_series ls
group by lane, series
having (select count(*) from lane_series where lane = ls.lane and series > ls.series) < 2
order by lane, series desc;
+------+--------+
| lane | series |
+------+--------+
| 1 | 688 |
| 1 | 685 |
| 2 | 775 |
| 2 | 666 |
+------+--------+
4 rows in set (0.00 sec)
答案 1 :(得分:3)
这个解决方案是MySQL最快的解决方案,适用于非常大的表,但它使用“时髦”的MySQL功能,所以不会用于其他数据库版本。
(编辑在应用逻辑之前对进行排序)
set @count:=-1, @lane:=0;
select lane, series
from (select lane, series from lane_series order by lane, series desc) x
where if(lane != @lane, @count:=-1, 0) is not null
and if(lane != @lane, @lane:=lane, lane) is not null
and (@count:=@count+1) < 2; -- Specify the number of row at top of each group here
要将此查询放在类固醇上,请在lane和series上定义一个索引:CREATE INDEX lane_series_idx on lane_series(lane, series);
它将执行(超快速)仅索引扫描 - 因此您的其他文本列不会影响它。
此查询的优点是:
这是测试输出:
create table lane_series (lane int, series int);
insert into lane_series values (1, 680),(1, 685),(1, 688),(2, 666),(2, 425),(2, 775);
-- Execute above query:
+------+--------+
| lane | series |
+------+--------+
| 1 | 688 |
| 1 | 685 |
| 2 | 775 |
| 2 | 666 |
+------+--------+
答案 2 :(得分:2)
这将有效,如果你知道你永远不会有第一名的关系:
SELECT lane,MAX(series)
FROM scores
GROUP BY lane
UNION
SELECT s.lane,MAX(s.series)
FROM scores AS s
JOIN (
SELECT lane,MAX(series) AS series
FROM scores
GROUP BY lane
) AS x ON (x.lane = s.lane)
WHERE s.series <> x.series
GROUP BY s.lane;
答案 3 :(得分:0)
我认为@ Bohemian的通用答案也可以写成连接而不是子查询,尽管它可能没什么区别:
select ls1.lane, ls1.series
from lane_series ls1 left join lane_series ls2 on lane
where ls1.series < ls2.series
group by ls1.lane, ls1.series
having count(ls2.series) < 2 -- Here's where you specify the number of top rows
order by ls1.lane, ls1.series desc;