MySQL獲取分組後的TOP 1和TOP N記錄

有時會碰到一些需求,查詢分組後的最大值,最小值所在的整行記錄或者分組後的top n行的記錄,在一些別的數據庫可能有窗口函數能夠方面的查出來,可是MySQL沒有這些函數,沒有直接的方法能夠查出來,可經過如下的方法來查詢。數據庫

 

準備工做

測試表結構以下:函數

root:test> show create table test1\G
*************************** 1. row ***************************
       Table: test1
Create Table: CREATE TABLE `test1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `course` varchar(20) DEFAULT NULL,
  `score` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

 插入數據:測試

insert into test1(name,course,score)
values
('張三','語文',80),
('李四','語文',90),
('王五','語文',93),
('張三','數學',77),
('李四','數學',68),
('王五','數學',99),
('張三','英語',90),
('李四','英語',50),
('王五','英語',89);

查看結果:spa

root:test>  select * from test1;
+----+--------+--------+-------+
| id | name   | course | score |
+----+--------+--------+-------+
|  1 | 張三   | 語文   |    80 |
|  2 | 李四   | 語文   |    90 |
|  3 | 王五   | 語文   |    93 |
|  4 | 張三   | 數學   |    77 |
|  5 | 李四   | 數學   |    68 |
|  6 | 王五   | 數學   |    99 |
|  7 | 張三   | 英語   |    90 |
|  8 | 李四   | 英語   |    50 |
|  9 | 王五   | 英語   |    89 |
+----+--------+--------+-------+

 

TOP 1

查詢每門課程分數最高的學生以及成績code

一、使用自鏈接【推薦】blog

root:test> select a.name,a.course,a.score from
    -> test1 a
    -> join (select course,max(score) score from test1 group by course) b 
    -> on a.course=b.course and a.score=b.score;
+--------+--------+-------+
| name   | course | score |
+--------+--------+-------+
| 王五   | 語文   |    93 |
| 王五   | 數學   |    99 |
| 張三   | 英語   |    90 |
+--------+--------+-------+
3 rows in set (0.00 sec)

 

二、使用相關子查詢數學

root:test> select name,course,score from test1 a
    -> where score=(select max(score) from test1 where a.course=test1.course);
+--------+--------+-------+
| name   | course | score |
+--------+--------+-------+
| 王五   | 語文   |    93 |
| 王五   | 數學   |    99 |
| 張三   | 英語   |    90 |
+--------+--------+-------+
3 rows in set (0.00 sec)

 

或者it

root:test> select name,course,score from test1 a
    -> where not exists(select 1 from test1 where a.course=test1.course and a.score < test1.score);
+--------+--------+-------+
| name   | course | score |
+--------+--------+-------+
| 王五   | 語文   |    93 |
| 王五   | 數學   |    99 |
| 張三   | 英語   |    90 |
+--------+--------+-------+
3 rows in set (0.00 sec)

 

 

TOP N

N>=1io

查詢每門課程前兩名的學生以及成績table

一、使用union all

若是結果集比較小,能夠用程序查詢單個分組結果後拼湊,也能夠使用union all

root:test> (select name,course,score from test1 where course='語文' order by score desc limit 2)
    -> union all
    -> (select name,course,score from test1 where course='數學' order by score desc limit 2)
    -> union all
    -> (select name,course,score from test1 where course='英語' order by score desc limit 2);
+--------+--------+-------+
| name   | course | score |
+--------+--------+-------+
| 王五   | 語文   |    93 |
| 李四   | 語文   |    90 |
| 王五   | 數學   |    99 |
| 張三   | 數學   |    77 |
| 張三   | 英語   |    90 |
| 王五   | 英語   |    89 |
+--------+--------+-------+
6 rows in set (0.01 sec)

 

二、自身左鏈接

root:test> select a.name,a.course,a.score
    -> from test1 a left join test1 b on a.course=b.course and a.score<b.score
    -> group by a.name,a.course,a.score
    -> having count(b.id)<2
    -> order by a.course,a.score desc;
+--------+--------+-------+
| name   | course | score |
+--------+--------+-------+
| 王五   | 數學   |    99 |
| 張三   | 數學   |    77 |
| 張三   | 英語   |    90 |
| 王五   | 英語   |    89 |
| 王五   | 語文   |    93 |
| 李四   | 語文   |    90 |
+--------+--------+-------+
6 rows in set (0.00 sec)

三、相關子查詢

root:test> select *
    -> from test1 a
    -> where 2>(select count(*) from test1 where course=a.course and score>a.score)
    -> order by a.course,a.score desc;
+----+--------+--------+-------+
| id | name   | course | score |
+----+--------+--------+-------+
|  6 | 王五   | 數學   |    99 |
|  4 | 張三   | 數學   |    77 |
|  7 | 張三   | 英語   |    90 |
|  9 | 王五   | 英語   |    89 |
|  3 | 王五   | 語文   |    93 |
|  2 | 李四   | 語文   |    90 |
+----+--------+--------+-------+
6 rows in set (0.01 sec)

四、使用用戶變量

root:test> set @num := 0, @course := '';
Query OK, 0 rows affected (0.00 sec)

root:test> 
root:test> select name, course, score
    -> from (
    ->    select name, course, score,
    ->       @num := if(@course = course, @num + 1, 1) as row_number,
    ->       @course := course as dummy
    ->   from test1
    ->   order by course, score desc
    -> ) as x where x.row_number <= 2;
+--------+--------+-------+
| name   | course | score |
+--------+--------+-------+
| 王五   | 數學   |    99 |
| 張三   | 數學   |    77 |
| 張三   | 英語   |    90 |
| 王五   | 英語   |    89 |
| 王五   | 語文   |    93 |
| 李四   | 語文   |    90 |
+--------+--------+-------+
6 rows in set (0.00 sec)
相關文章
相關標籤/搜索