分组取前N记录-- 一道淘宝的考察sql语句的面试题

因为一道淘宝面试的sql语句题目开始思考如何取出每组的前N条记录,在网上找了2篇比较好的博文转载下!

 

经常看到问题,如何取出每组的前N条记录。方便大家参考于是便把常见的几种解法列出于下。

问题:有表 如下,要求取出各班前两名(允许并列第二)
Table1
+----+------+------+-----+
| id |SName |ClsNo |Score|
+----+------+------+-----+
|  1 |AAAA  |  C1  | 67  |
|  2 |BBBB  |  C1  | 55  |
|  3 |CCCC  |  C1  | 67  |
|  4 |DDDD  |  C1  | 65  |
|  5 |EEEE  |  C1  | 95  |
|  6 |FFFF  |  C2  | 57  |
|  7 |GGGG  |  C2  | 87  |
|  8 |HHHH  |  C2  | 74  |
|  9 |IIII  |  C2  | 52  |
| 10 |JJJJ  |  C2  | 81  |
| 11 |KKKK  |  C2  | 67  |
| 12 |LLLL  |  C2  | 66  |
| 13 |MMMM  |  C2  | 63  |
| 14 |NNNN  |  C3  | 99  |
| 15 |OOOO  |  C3  | 50  |
| 16 |PPPP  |  C3  | 59  |
| 17 |QQQQ  |  C3  | 66  |
| 18 |RRRR  |  C3  | 76  |
| 19 |SSSS  |  C3  | 50  |
| 20 |TTTT  |  C3  | 50  |
| 21 |UUUU  |  C3  | 64  |
| 22 |VVVV  |  C3  | 74  |
+----+------+------+-----+

结果如下
+----+------+------+-----+
| id |SName |ClsNo |Score|
+----+------+------+-----+
|  5 |EEEE  |  C1  | 95  |
|  1 |AAAA  |  C1  | 67  |
|  3 |CCCC  |  C1  | 67  |
|  7 |GGGG  |  C2  | 87  |
| 10 |JJJJ  |  C2  | 81  |
| 14 |NNNN  |  C3  | 99  |
| 18 |RRRR  |  C3  | 76  |
+----+------+------+-----+

方法一:

1 select a.id,a.SName,a.ClsNo,a.Score
2 from Table1 a left join Table1 b on a.ClsNo=b.ClsNo and a.Score<b.Score
3 group by a.id,a.SName,a.ClsNo,a.Score
4 having count(b.id)<2
5 order by a.ClsNo,a.Score desc

 

方法二:

1 select *
2 from Table1 a
3 where 2>(select count(*) from Table1 where ClsNo=a.ClsNo and Score>a.Score)
4 order by a.ClsNo,a.Score desc

 

 

方法三:

1 select *
2 from Table1 a
3 where id in (select id from Table1 where ClsNo=a.ClsNo order by Score desc limit 2)
4 order by a.ClsNo,a.Score desc

 

 

方法....

这里列出了多种SQL语句的实现方法,有些是MySQL特有的(Limit, 其它数据库可根据实际更改,比如oracle的rownum,MS SQL SERVER 的 top,..),有时是SQL标准支持的。但效率上和应用的场合或许不同。具体应用时可根据实际表中的记录情况,索引情况进行选择。

 

 

特例 N=1 ,即取最大的/最小的一条记录。
+----+------+------+-----+
| id |SName |ClsNo |Score|
+----+------+------+-----+
|  5 |EEEE  |  C1  | 95  |
|  7 |GGGG  |  C2  | 87  |
| 14 |NNNN  |  C3  | 99  |
+----+------+------+-----+

 

 1 select * 
 2 from Table1 a
 3 where not exists (select 1 from Table1 where ClsNo=a.ClsNo and Score>a.Score);
 4 
 5  
 6 
 8 
 9 select a.* 
10 from Table1 a inner join (select ClsNo, max(Score) as mScore from Table1 group by ClsNo) b
11  on a.ClsNo=b.ClsNo and a.Score=b.Score
12 
13  
14 
15 select *
16 from (select * from Table1 order by Score desc) t
17 group by ClsNo

转自:http://blog.csdn.net/acmain_chm/article/details/4126306

 

 

现引入一道淘宝的sql语句面试题:要求用一条sql语句查出按grade排名男生前5名和女生前5名

 1 CREATE TABLE `t_stu` (  
 2 `id` int(4) NOT NULL DEFAULT '0',  
 3 `name` varchar(16) DEFAULT NULL,  
 4 `gender` int(2) DEFAULT NULL,  
 5 `grade` int(4) DEFAULT NULL,  
 6  PRIMARY KEY (`id`)  
 7 )DEFAULT CHARSET=utf8;
 8 
 9 
10 insert into t_stu values(1,"ElenaA",0,90);  
11 insert into t_stu values(2,"ElenaB",1,92);
12 insert into t_stu values(3,"ElenaC",1,20);
13 insert into t_stu values(4,"ElenaD",0,80);
14 insert into t_stu values(5,"ElenaE",1,20);
15 insert into t_stu values(6,"ElenaF",0,40);
16 insert into t_stu values(7,"ElenaG",0,50);
17 insert into t_stu values(8,"ElenaH",1,20);
18 insert into t_stu values(9,"ElenaI",0,30);
19 insert into t_stu values(10,"ElenaG",1,12);
20 insert into t_stu values(11,"ElenaK",0,42);
21 insert into t_stu values(12,"ElenaM",1,52);
22 insert into t_stu values(13,"ElenaN",0,62);
23 insert into t_stu values(14,"ElenaO",1,72);
24 insert into t_stu values(15,"ElenaP",1,22);
25 insert into t_stu values(16,"ElenaQ",1,12);
26 insert into t_stu values(17,"ElenaR",0,82);
27 insert into t_stu values(18,"ElenaS",0,99);
28 
29 #抽取出来的4种解决办法
30 #1
31 select * from t_stu a where 5>(select count(*) FROM t_stu where gender=a.gender AND grade>a.grade) order by a.grade desc  
32 
33 #2
34 select * from t_stu where grade in (select * from ( (select distinct(grade) from t_stu where gender=1 order by grade desc limit 5) a)) and gender=1;
35 
36 #3
37 SELECT a.* FROM t_stu a INNER JOIN ((SELECT GROUP_CONCAT(Id) AS Id FROM t_stu where gender=1 GROUP BY grade DESC LIMIT 5) union all (SELECT GROUP_CONCAT(Id) AS Id FROM t_stu where gender=0 GROUP BY grade DESC LIMIT 5)) b ON FIND_IN_SET(a.id,b.Id)>0 ORDER BY grade DESC ;
38 
39 #4
40 SELECT * FROM `t_stu` a WHERE grade>=IFNULL((SELECT grade FROM `t_stu` WHERE gender=a.gender order BY grade DESC LIMIT 4,1),0);

 

转自:http://topic.csdn.net/u/20120515/14/a84130bd-3a2e-4810-a229-0e5394c43387.html

posted @ 2012-09-02 11:36  llsun  阅读(728)  评论(0编辑  收藏  举报