不少查詢均可以用經典的學生-課程-成績案例來表示,下面是一些我在筆試或面試中遇到的經典題型。這些題目沒有涉及到索引,函數,存儲過程等高級功能,都是一些基本的查詢語句,但難度卻不小。mysql
create table student( id int unsigned primary key auto_increment, name char(10) not null ); insert into student(name) values('張三'),('李四'); create table course( id int unsigned primary key auto_increment, name char(20) not null ); insert into course(name) values('語文'),('數學'); create table student_course( sid int unsigned, cid int unsigned, score int unsigned not null, foreign key (sid) references student(id), foreign key (cid) references course(id), primary key(sid, cid) ); insert into student_course values(1,1,80),(1,2,90),(2,1,90),(2,2,70);
select id,name from student where name in ( select name from student group by name having(count(*) > 1) ) order by name;
咱們常常須要查詢某一列重複的行,通常經過group by(有重複的列)而後取count>1的值。 關係型數據庫有他的侷限性, 有些看似簡單的查詢寫出來的sql很複雜,並且效率也會很低。面試
select sid,avg(score) as avg_score from student_course group by sid having(avg_score<60);
group by和having是最常考的。 where子句中不能用匯集函數做爲條件表達式,可是having短語能夠,where和having的區別在於對用對象不一樣,where做用於記錄,having做用於組。sql
select distinct sid from student_course where sid not in (select sid from student_course where score < 80);
用到反向思想,其實就是數理邏輯中的∀x:P和¬∃x:¬P是等價的。數據庫
select name,sum(score) total from student,student_course where student.id=student_course.sid group by sid;
更保險的作法應該是使用 左外鏈接函數
select name,sum(score) from student left join student_course on student.id=student_course.sid group by sid;
select sid,sum(score) as sum_score from student_course group by sid having sum_score>=all( select sum(score) from student_course group by sid );
由於order by中可使用匯集函數,最簡單的方法是:code
select sid,sum(score) as sum_score from student_course group by sid order by sum_score desc limit 1;
同理能夠查總成績的前三名。對象
這是個查詢 第N大數 的問題。 咱們先查出第2高的成績:索引
select min(score) from student_course where cid = 1 group by score order by score desc limit 2;
使用這種方式是錯的,由於做用的前後順序是group by->min->order by->limit,mysql提供了limit offset,size這種方式來取第N大的值,所以正確的作法是:ci
select score from student_course where cid = 1 group by score order by score desc limit 1,1;
而後再取出該成績對應的學生:rem
select * from student_course where cid=1 and score = ( select score from student_course where cid = 1 group by score order by score desc limit 1,1 );
相似的,能夠查詢 某個值第N高 的記錄。
select sid,cid,max(score) from student_course group by cid;
然而上面是不對的,由於 使用了group by的查詢字段只能是group by中的字段或者彙集函數或者是每一個分組內均相同的字段。 雖然不會報錯,可是sid是無效的,若是去掉sid的話只能查出沒門課程的最高分,不包含學生id。 本題的正確解法是使用相關嵌套查詢:
select * from student_course as x where score>=( select max(score) from student_course as y where cid=x.cid );
相關嵌套查詢也就是在進行內層查詢的時候須要用到外層查詢,有一些注意事項:
select * from student_course x where 2>( select count(*) from student_course y where y.cid=x.cid and y.score>x.score ) order by cid,score desc;
這也是一個相關嵌套查詢,對於每個分數,若是同一門課程下只有0個、1個分數比這個分數還高,那麼這個分數確定是前2名之一
select a.name, b.name
from team a, team b
where a.name < b.name
其實就是一個表和本身鏈接查詢。
年 季度 銷售
1991 1 11
1991 2 12
1991 3 13
1991 4 14
1992 1 21
1992 2 22
1992 3 23
1992 4 24
要求:寫一個SQL語句查詢出以下所示的結果。
年 一季度 二季度 三季度 四季度
1991 11 12 13 14
1992 21 22 23 24
select 年, sum(case when 季度=1 then 銷售量 else 0 end) as 一季度, sum(case when 季度=2 then 銷售量 else 0 end) as 二季度, sum(case when 季度=3 then 銷售量 else 0 end) as 三季度, sum(case when 季度=4 then 銷售量 else 0 end) as 四季度 from sales group by 年;
同理,若是要查詢每一個人的每門課的成績可使用以下sql
create view temp as select student.name as sname,course.name as cname,score from student_course join (student,course) on(student_course.sid=student.id and student_course.cid=course.id); select sname, sum(case when cname='語文' then score else 0 end) as 語文, sum(case when cname='數學' then score else 0 end) as 數學 from temp group by sname;
固然若是新增了一門課,第二條sql就須要跟着變。