mysql group by first_MySQL中,Group By后,取每组的Top N条记录

转载自:http://www.geeklab.info/2012/11/mysql-how-to-get-top-n-rows-for-each-group/

We have the following table and data:

CREATE TEMPORARY TABLE girls(

name text,

haircolor text,

score INT

);

INSERT INTO girls VALUES ('Megan','brunette',9);

INSERT INTO girls VALUES ('Tiffany','brunette',5);

INSERT INTO girls VALUES ('Kimberly','brunette',7);

INSERT INTO girls VALUES ('Hester','blonde',10);

INSERT INTO girls VALUES ('Caroline','blonde',5);

SELECT * from girls;

+----------+-----------+-------+

| name | haircolor | score |

+----------+-----------+-------+

| Megan | brunette | 9 |

| Tiffany | brunette | 5 |

| Kimberly | brunette | 7 |

| Hester | blonde | 10 |

| Caroline | blonde | 5 |

+----------+-----------+-------+

5 rows in set (0.00 sec)

Session Variables

MySQL, at least on the versions I’ve checked, does not support ROW_NUMBER() function that can assign a sequence number within a group, the MySQL session variables can be used to build a workaround. Session variables do not need to be declared first and can be used to do calculations and perform actions based on them. They appear to require initialization. For instance:

@previous_haircolor := haircolor

This code is executed for each row and stores the value of haircolor column to @current_haircolor variable.

@girl_rank := IF(@previous_haircolor = haircolor, @girl_rank + 1, 1)

In this code, if @previous_haircolor equals the haircolor on the current row we increment rank, otherwise set it to 1. For the first row @previous_haircolor is NULL, so rank is also initialized to 1.

For correct ranking, we need to have ORDER BY haircolor,score DESC

So if we run:

SELECT @previous_haircolor := null; /* Initialize first, or girl_rank will always be 1 */

SELECT

name,haircolor,score,

@girl_rank := IF(@previous_haircolor = haircolor, @girl_rank + 1, 1) AS girl_rank,

@previous_haircolor := haircolor

FROM girls

ORDER BY haircolor,score DESC

We get the list of girls ranked by their score within the haircolor group:

+----------+-----------+-------+-----------+----------------------------------+

| name | haircolor | score | girl_rank | @previous_haircolor := haircolor |

+----------+-----------+-------+-----------+----------------------------------+

| Hester | blonde | 10 | 1 | blonde |

| Caroline | blonde | 5 | 2 | blonde |

| Megan | brunette | 9 | 1 | brunette |

| Kimberly | brunette | 7 | 2 | brunette |

| Tiffany | brunette | 5 | 3 | brunette |

+----------+-----------+-------+-----------+----------------------------------+

5 rows in set (0.00 sec)

When we have a rank assigned to each girl within her haircolor group, we can request the wanted range:

-- Get top 2 for each haircolor

SELECT name, haircolor, score

FROM (/*subquery above*/) ranked

WHERE girl_rank <= 2;

So the full query is:

SELECT @previous_haircolor := null; /* Initialize first, or girl_rank will always be 1 */

SELECT name, haircolor, score

FROM (SELECT

name,haircolor,score,

@girl_rank := IF(@previous_haircolor = haircolor, @girl_rank + 1, 1) AS girl_rank,

@previous_haircolor := haircolor

FROM girls

ORDER BY haircolor,score DESC) ranked

WHERE girl_rank <= 2;

Using oracle, SQL Server and PostgreSQL: ROW_NUMBER()

In Oracle, SQL Server and PostgreSQL (version 8.4 and higher) you can achieve the same functionality using ROW_NUMBER function:

SELECT name,haircolor,score

FROM

(SELECT name,haircolor,score

ROW_NUMBER() OVER (PARTITION BY haircolor ORDER BY score DESC) as girl_rank

FROM girls) ranked

WHERE girl_rank <= 2;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值