1. 程式人生 > >mysql:10道mysql查詢語句面試題

mysql:10道mysql查詢語句面試題

表結構

  • 學生表student(id,name)
  • 課程表course(id,name)
  • 學生課程表student_course(sid,cid,score)

建立表的sql程式碼

```sql
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);
```

問題

  1. 查詢student表中重名的學生,結果包含id和name,按name,id升序

    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很複雜,而且效率也會很低。

     

  2. 在student_course表中查詢平均分不及格的學生,列出學生id和平均分

    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作用於組

     

  3. 在student_course表中查詢每門課成績都不低於80的學生id

    select distinct sid
    from student_course
    where sid not in ( select sid from student_course where score < 80);
    用到反向思想,其實就是數理邏輯中的∀x:P和¬∃x:¬P是等價的。

     

  4. 查詢每個學生的總成績,結果列出學生姓名和總成績 如果使用下面的sql會過濾掉沒有成績的人

    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;
    

     

  5. 總成績最高的學生,結果列出學生id和總成績 下面的sql效率很低,因為要重複計算所有的總成績。

    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中可以使用聚集函式,最簡單的方法是:
    select sid,sum(score) as sum_score
    from student_course group by sid
    order by sum_score desc limit 1;
    
    同理可以查總成績的前三名。

     

  6. 在student_course表查詢課程1成績第2高的學生,如果第2高的不止一個則列出所有的學生

    這是個查詢 第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大的值,因此正確的做法是:
    select score from student_course where cid = 1 group by score order by score desc limit 1,1;
    
    然後再取出該成績對應的學生:
    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高 的記錄。

     

  7. 在student_course表查詢各科成績最高的學生,結果列出學生id、課程id和對應的成績 你可能會這樣寫:

    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);
    
    相關巢狀查詢也就是在進行內層查詢的時候需要用到外層查詢,有一些注意事項:

     

    • 子查詢一定要有括號
    • as可以省略
    • 使用相關查詢;>=max等價於>=all,但是聚合函式比使用any或all效率高
  8. 在student_course表中查詢每門課的前2名,結果按課程id升序,同一課程按成績降序 這個問題也就是取每組的前N條紀錄,類似的查詢在csdn上也有徵集答案

    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名之一

     

  9. 一個叫team的表,裡面只有一個欄位name,一共有4條紀錄,分別是a,b,c,d,對應四個球隊,兩兩進行比賽,用一條sql語句顯示所有可能的比賽組合

    select a.name, b.name
    from team a, team b
    where a.name < b.name
    
    其實就是一個表和自己連線查詢。

     

  10. 題目:資料庫中有一張如下所示的表,表名為sales。

    季度 銷售
    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就需要跟著變。