查询:
SELECT
year, id, rate
FROM h
WHERE year BETWEEN 2000 AND 2009
AND id IN (SELECT rid FROM table2)
GROUP BY id, year
ORDER BY id, rate DESC
收益率:
year id rate
2006 p01 8
2003 p01 7.4
2008 p01 6.8
2001 p01 5.9
2007 p01 5.3
2009 p01 4.4
2002 p01 3.9
2004 p01 3.5
2005 p01 2.1
2000 p01 0.8
2001 p02 12.5
2004 p02 12.4
2002 p02 12.2
2003 p02 10.3
2000 p02 8.7
2006 p02 4.6
2007 p02 3.3
我想要的是每个id只有前5个结果:
2006 p01 8
2003 p01 7.4
2008 p01 6.8
2001 p01 5.9
2007 p01 5.3
2001 p02 12.5
2004 p02 12.4
2002 p02 12.2
2003 p02 10.3
2000 p02 8.7
是否有一种方法来做到这一点,使用一些限制之类的修饰符,在GROUP BY中工作?
试试这个:
SELECT h.year, h.id, h.rate
FROM (SELECT h.year, h.id, h.rate, IF(@lastid = (@lastid:=h.id), @index:=@index+1, @index:=0) indx
FROM (SELECT h.year, h.id, h.rate
FROM h
WHERE h.year BETWEEN 2000 AND 2009 AND id IN (SELECT rid FROM table2)
GROUP BY id, h.year
ORDER BY id, rate DESC
) h, (SELECT @lastid:='', @index:=0) AS a
) h
WHERE h.indx <= 5;
你想找出每个组的前n行。这个答案使用与OP不同的示例数据提供了一个通用的解决方案。
在MySQL 8或更高版本中,您可以根据top 5的确切定义使用ROW_NUMBER, RANK或DENSE_RANK函数。下面是这些函数根据值降序排序生成的数字。注意领带是如何处理的:
pkid |
catid |
value |
row_number |
rank |
dense_rank |
1 |
p01 |
100 |
*1 |
*1 |
*1 |
2 |
p01 |
90 |
*2 |
*2 |
*2 |
3 |
p01 |
90 |
*3 |
*2 |
*2 |
4 |
p01 |
80 |
*4 |
*4 |
*3 |
5 |
p01 |
80 |
*5 |
*4 |
*3 |
6 |
p01 |
80 |
6 |
*4 |
*3 |
7 |
p01 |
70 |
7 |
7 |
*4 |
8 |
p01 |
60 |
8 |
8 |
*5 |
9 |
p01 |
50 |
9 |
9 |
6 |
10 |
p01 |
40 |
10 |
10 |
7 |
一旦你选择了函数,就像这样使用它:
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY value DESC) AS n
FROM t
) AS x
WHERE n <= 5
DB < >小提琴
在MySQL 5。X,你可以使用穷人的排名超过分区,以达到预期的结果:外部连接表本身和每一行,计算它之前的行数(例如,前一行可以是一个较高的值)。
下面将产生类似RANK函数的结果:
SELECT t.pkid, t.catid, t.value, COUNT(b.value) + 1 AS rank
FROM t
LEFT JOIN t AS b ON b.catid = t.catid AND b.value > t.value
GROUP BY t.pkid, t.catid, t.value
HAVING COUNT(b.value) + 1 <= 5
ORDER BY t.catid, t.value DESC, t.pkid
进行以下更改以产生与DENSE_RANK函数类似的结果:
COUNT(DISTINCT b.value)
或进行以下更改,以产生类似于ROW_NUMBER函数的结果:
ON b.catid = t.catid AND (b.value > t.value OR b.value = t.value AND b.pkid < t.pkid)
DB < >小提琴
这需要一系列子查询对值进行排序、限制,然后在分组时执行求和
@Rnk:=0;
@N:=2;
select
c.id,
sum(c.val)
from (
select
b.id,
b.bal
from (
select
if(@last_id=id,@Rnk+1,1) as Rnk,
a.id,
a.val,
@last_id=id,
from (
select
id,
val
from list
order by id,val desc) as a) as b
where b.rnk < @N) as c
group by c.id;
试试这个:
SELECT h.year, h.id, h.rate
FROM (SELECT h.year, h.id, h.rate, IF(@lastid = (@lastid:=h.id), @index:=@index+1, @index:=0) indx
FROM (SELECT h.year, h.id, h.rate
FROM h
WHERE h.year BETWEEN 2000 AND 2009 AND id IN (SELECT rid FROM table2)
GROUP BY id, h.year
ORDER BY id, rate DESC
) h, (SELECT @lastid:='', @index:=0) AS a
) h
WHERE h.indx <= 5;