mysql經典50道基礎練習題(附加答案)


一、環境准備

  sql腳本如下:

create table Student(sid varchar(10),sname varchar(10),sage datetime,ssex nvarchar(10));
insert into Student values('01' , '趙雷' , '1990-01-01' , '');
insert into Student values('02' , '錢電' , '1990-12-21' , '');
insert into Student values('03' , '孫風' , '1990-05-20' , '');
insert into Student values('04' , '李雲' , '1990-08-06' , '');
insert into Student values('05' , '周梅' , '1991-12-01' , '');
insert into Student values('06' , '吳蘭' , '1992-03-01' , '');
insert into Student values('07' , '鄭竹' , '1989-07-01' , '');
insert into Student values('08' , '王菊' , '1990-01-20' , '');
create table Course(cid varchar(10),cname varchar(10),tid varchar(10));
insert into Course values('01' , '語文' , '02');
insert into Course values('02' , '數學' , '01');
insert into Course values('03' , '英語' , '03');
create table Teacher(tid varchar(10),tname varchar(10));
insert into Teacher values('01' , '張三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');
create table SC(sid varchar(10),cid varchar(10),score decimal(18,1));
insert into SC values('01' , '01' , 80);
insert into SC values('01' , '02' , 90);
insert into SC values('01' , '03' , 99);
insert into SC values('02' , '01' , 70);
insert into SC values('02' , '02' , 60);
insert into SC values('02' , '03' , 80);
insert into SC values('03' , '01' , 80);
insert into SC values('03' , '02' , 80);
insert into SC values('03' , '03' , 80);
insert into SC values('04' , '01' , 50);
insert into SC values('04' , '02' , 30);
insert into SC values('04' , '03' , 20);
insert into SC values('05' , '01' , 76);
insert into SC values('05' , '02' , 87);
insert into SC values('06' , '01' , 31);
insert into SC values('06' , '03' , 34);
insert into SC values('07' , '02' , 89);
insert into SC values('07' , '03' , 98);

腳本說明:

  一共4張表,分別對應學生信息(Student)、課程信息(Course)、教師信息(Teacher)以及成績信息(SC)

 

二、正文部分

  1、查詢"01"課程比"02"課程成績高的學生的信息及課程分數 

SELECT student.*,t3.sid FROM
(SELECT t1.sid,t1.score FROM (SELECT sid,score FROM sc WHERE cid = "01") as t1
JOIN
(SELECT sid,score FROM sc WHERE cid = "02") as t2
ON 
t1.sid = t2.sid WHERE t1.score > t2.score) as t3 
JOIN student
ON t3.sid = student.sid;

結果:

+-----+-------+---------------------+------+-----+
| sid | sname | sage                | ssex | sid |
+-----+-------+---------------------+------+-----+
| 02  | 錢電  | 1990-12-21 00:00:00 || 02  |
| 04  | 李雲  | 1990-08-06 00:00:00 || 04  |
+-----+-------+---------------------+------+-----+
2 rows in set

解析:

先將課程為01和02的課程及對應分數篩選出來,再join,on為01.sid = 02.sid,條件為01.score >02.score,結果'存'為新表t3,再將Student表和t3表join

   2、查詢學生選課存在" 01 "課程但可能不存在" 02 "課程的情況(不存在時顯示為 null)

SELECT * FROM
(SELECT * FROM sc WHERE cid = "01") as t1 
LEFT JOIN 
(SELECT * FROM sc WHERE cid = "02") as t2
ON t1.sid = t2.sid;

結果:

+-----+-----+-------+------+------+-------+
| sid | cid | score | sid  | cid  | score |
+-----+-----+-------+------+------+-------+
| 01  | 01  | 80.0  | 01   | 02   | 90.0  |
| 02  | 01  | 70.0  | 02   | 02   | 60.0  |
| 03  | 01  | 80.0  | 03   | 02   | 80.0  |
| 04  | 01  | 50.0  | 04   | 02   | 30.0  |
| 05  | 01  | 76.0  | 05   | 02   | 87.0  |
| 06  | 01  | 31.0  | NULL | NULL | NULL  |
+-----+-----+-------+------+------+-------+
6 rows in set

解析:

即找出學生選了01課程沒有選02課程的情況,用left join即可

  3、查詢平均成績大於等於 60 分的同學的學生編號和學生姓名和平均成績

#多表聯合查詢
SELECT  sc.sid,student.sname,avg(sc.score) FROM sc ,student WHERE sc.sid = student.sid  GROUP BY  sc.sid  HAVING avg(sc.score) > 60;
#多表連接查詢
SELECT  sc.sid,student.sname,avg(sc.score) FROM sc JOIN student on sc.sid = student.sid  GROUP BY  sc.sid  HAVING avg(sc.score) > 60;

結果:

+-----+-------+---------------+
| sid | sname | avg(sc.score) |
+-----+-------+---------------+
| 01  | 趙雷  | 89.66667      |
| 02  | 錢電  | 70.00000      |
| 03  | 孫風  | 80.00000      |
| 05  | 周梅  | 81.50000      |
| 07  | 鄭竹  | 93.50000      |
+-----+-------+---------------+
5 rows in set

解析:

首先確定的是兩張表,student和sc,這里使用多表聯合查詢和多表連接查的方式都可以,關聯條件是sid,然后分組,最后加一個having函數,條件是平均成績大於60,即可查詢出來

  4、查詢在 SC 表存在成績的學生信息

#多表聯合查詢方式
SELECT  t1.*,t2.score FROM student t1, sc t2 WHERE t1.sid = t2.sid  GROUP BY t1.sid;

#多表連接查詢方式
SELECT a.*,b.score FROM student as a 
    JOIN sc AS b 
    ON a.sid = b.sid 
        GROUP BY a.sid;

結果:

+-----+-------+---------------------+------+-------+
| sid | sname | sage                | ssex | score |
+-----+-------+---------------------+------+-------+
| 01  | 趙雷  | 1990-01-01 00:00:00 || 80.0  |
| 02  | 錢電  | 1990-12-21 00:00:00 || 70.0  |
| 03  | 孫風  | 1990-05-20 00:00:00 || 80.0  |
| 04  | 李雲  | 1990-08-06 00:00:00 || 50.0  |
| 05  | 周梅  | 1991-12-01 00:00:00 || 76.0  |
| 06  | 吳蘭  | 1992-03-01 00:00:00 || 31.0  |
| 07  | 鄭竹  | 1989-07-01 00:00:00 || 89.0  |
+-----+-------+---------------------+------+-------+
7 rows in set

解析:

確定是兩個表,student和sc,關聯條件還是sid消除笛卡爾積,然后再group by,最后select 取需要的信息

  5、查詢所有同學的學生編號、學生姓名、選課總數、所有課程的成績總和

#多表聯合查詢方式
SELECT t1.sid as 學生編號,t1.sname as 學生姓名,COUNT(t2.cid) as 選課總數,SUM(t2.score) as 課程成績總和  FROM student t1, sc t2 WHERE t1.sid = t2.sid  GROUP BY t1.sid;

#多表連接查詢
SELECT t1.sid as 學生編號,t1.sname as 學生姓名,COUNT(t2.cid) as 選課總數,SUM(t2.score) as 課程成績總和  FROM student t1 JOIN sc t2 ON t1.sid = t2.sid  GROUP BY t1.sid;

結果:

+----------+----------+----------+--------------+
| 學生編號 | 學生姓名 | 選課總數 | 課程成績總和 |
+----------+----------+----------+--------------+
| 01       | 趙雷     |        3 | 269.0        |
| 02       | 錢電     |        3 | 210.0        |
| 03       | 孫風     |        3 | 240.0        |
| 04       | 李雲     |        3 | 100.0        |
| 05       | 周梅     |        2 | 163.0        |
| 06       | 吳蘭     |        2 | 65.0         |
| 07       | 鄭竹     |        2 | 187.0        |
+----------+----------+----------+--------------+
7 rows in set

解析:

兩個聚合函數(統計函數)一個count(cid),一個sum(score),同樣join student表和sc表,再group by sid即可

  6、查詢「李」姓老師的數量

SELECT COUNT(t.tid) FROM teacher t WHERE t.tname like "%%";

結果:

+--------------+
| COUNT(t.tid) |
+--------------+
|            1 |
+--------------+
1 row in set

解析:

count加條件函數加通配符即可

  7、查詢學過「張三」老師授課的同學的信息

SELECT f.*,e.tname FROM 
    (SELECT d.sid,c.tname FROM 
        (SELECT a.tname,b.cid FROM teacher AS a
            JOIN course AS b 
            ON a.tid = b.tid
                WHERE a.tname = '張三') AS c
        JOIN sc AS d
        ON c.cid = d.cid) AS e
JOIN student AS f
ON e.sid = f.sid

結果:

+-----+-------+---------------------+------+-------+
| sid | sname | sage                | ssex | tname |
+-----+-------+---------------------+------+-------+
| 01  | 趙雷  | 1990-01-01 00:00:00 || 張三  |
| 02  | 錢電  | 1990-12-21 00:00:00 || 張三  |
| 03  | 孫風  | 1990-05-20 00:00:00 || 張三  |
| 04  | 李雲  | 1990-08-06 00:00:00 || 張三  |
| 05  | 周梅  | 1991-12-01 00:00:00 || 張三  |
| 07  | 鄭竹  | 1989-07-01 00:00:00 || 張三  |
+-----+-------+---------------------+------+-------+
6 rows in set

解析:

四表連接,teacher表里的tid與course表里的tid,條件為tname=‘張三’,再course表里的cid與sc表里的cid,最后sc表里的sid與student里的sid

  8、查詢沒有學全所有課程的同學的信息

SELECT a.*,count(b.cid) AS 所學課程數
FROM student AS a
    LEFT JOIN sc AS b
    ON a.sid = b.sid
        GROUP BY b.sid
            HAVING COUNT(b.cid)< (SELECT COUNT(c.cid) FROM course as c);

結果:

+-----+-------+---------------------+------+------------+
| sid | sname | sage                | ssex | 所學課程數 |
+-----+-------+---------------------+------+------------+
| 05  | 周梅  | 1991-12-01 00:00:00 ||          2 |
| 06  | 吳蘭  | 1992-03-01 00:00:00 ||          2 |
| 07  | 鄭竹  | 1989-07-01 00:00:00 ||          2 |
| 08  | 王菊  | 1990-01-20 00:00:00 ||          0 |
+-----+-------+---------------------+------+------------+

解析:

先查詢總課程數,再查詢所有同學的信息,篩選條件為其所學課程數小於總課程數

  9、查詢至少有一門課與學號為" 01 "的同學所學相同的同學的信息

SELECT b.* FROM student AS b
    JOIN sc AS a 
    ON b.sid  = a.sid 
        WHERE a.cid in 
                    (SELECT a.cid FROM sc AS a WHERE a.sid = '01') 
        GROUP BY b.sid 
             HAVING b.sid != '01';

結果:

+-----+-------+---------------------+------+
| sid | sname | sage                | ssex |
+-----+-------+---------------------+------+
| 02  | 錢電  | 1990-12-21 00:00:00 ||
| 03  | 孫風  | 1990-05-20 00:00:00 ||
| 04  | 李雲  | 1990-08-06 00:00:00 ||
| 05  | 周梅  | 1991-12-01 00:00:00 ||
| 06  | 吳蘭  | 1992-03-01 00:00:00 ||
| 07  | 鄭竹  | 1989-07-01 00:00:00 ||
+-----+-------+---------------------+------+
6 rows in set

解析:

#先從成績表里查詢學號為01的同學所學的課程編號,篩選條件為sc.cid in 01同學所學編號,再使用學生表和成績表兩表關聯,關聯字段為sid,並且把課程編號作為子查詢的條件,刷選,然后再group by sid 最后通過having篩選sid 不等於01

  10、查詢和" 01 "號的同學學習的課程完全相同的其他同學的信息

SELECT t2.*, count(t3.cid) 
FROM student t2 JOIN sc t3 
ON t2.sid = t3.sid WHERE t2.sid != "01" GROUP BY t2.sid 
HAVING count(t3.cid) = ( SELECT COUNT(*) FROM sc t1 WHERE t1.sid = "01" );

結果:

+-----+-------+---------------------+------+---------------+
| sid | sname | sage                | ssex | count(t3.cid) |
+-----+-------+---------------------+------+---------------+
| 02  | 錢電  | 1990-12-21 00:00:00 ||             3 |
| 03  | 孫風  | 1990-05-20 00:00:00 ||             3 |
| 04  | 李雲  | 1990-08-06 00:00:00 ||             3 |
+-----+-------+---------------------+------+---------------+
3 rows in set

解析:

先從成績表中查詢學號為01的總課程數,然后使用學生表和成績表關聯查詢,關聯字段為sid,消除笛卡爾積,where條件語句過濾學號01,並且用學號字段分組,並且使用having函數,統計課程總數=學號為1的課程總數

  11、查詢沒學過"張三"老師講授的任一門課程的學生姓名

SELECT student.sname FROM student 
    WHERE student.sid NOT IN 
        (SELECT sc.sid FROM sc     
                    JOIN course 
                    ON sc.cid=course.cid
                    JOIN teacher 
                    ON course.tid=teacher.tid 
        WHERE tname='張三' )

結果:

+-------+
| sname |
+-------+
| 吳蘭  |
| 王菊  |
+-------+
2 rows in set

解析:

先找出所有學生選課信息及sid,再找出張三老師授課課程,將其連接,再用student里的sid not in 前面的sid

  12、查詢兩門及其以上不及格課程的同學的學號,姓名及其平均成績

SELECT c.sname,b.* FROM student as c
JOIN
(
(SELECT sid ,COUNT(cid) FROM sc WHERE score < 60 GROUP BY sid HAVING COUNT(cid) >=2) as a


#找出平均成績
JOIN
(SELECT sid,avg(score) FROM sc GROUP BY sid ) as b
 ON a.sid = b.sid)  
ON c.sid = b.sid

結果:

+-------+-----+------------+
| sname | sid | avg(score) |
+-------+-----+------------+
| 李雲  | 04  | 33.33333   |
| 吳蘭  | 06  | 32.50000   |
+-------+-----+------------+
2 rows in set

解析:

先查詢出不及格兩門或兩門以上的數據,再查詢出不及格的平均成績,再三張表嵌套關聯

  13、查詢" 01 "課程分數小於 60,按分數降序排列的學生信息

SELECT b.* ,a.score from student b  JOIN (SELECT  * FROM sc WHERE cid = "01" AND score < 60  ORDER BY score DESC ) as a  ON a.sid = b.sid ;

結果:

+-----+-------+---------------------+------+-------+
| sid | sname | sage                | ssex | score |
+-----+-------+---------------------+------+-------+
| 04  | 李雲  | 1990-08-06 00:00:00 || 50.0  |
| 06  | 吳蘭  | 1992-03-01 00:00:00 || 31.0  |
+-----+-------+---------------------+------+-------+
2 rows in set

解析:

先查詢出01課程分數小於60的sid ,按照分數降序,然后和學生表關聯

  14、按平均成績從高到低顯示所有學生的所有課程的成績以及平均成績

 SELECT a.sid,a.score,a.cid,b.`平均成績` FROM sc a JOIN 
(SELECT sid,avg(score) as 平均成績 FROM sc GROUP BY sid ) as b ON a.sid = b.sid ORDER BY b.`平均成績` DESC;

結果:

+-----+-------+-----+----------+
| sid | score | cid | 平均成績 |
+-----+-------+-----+----------+
| 07  | 89.0  | 02  | 93.50000 |
| 07  | 98.0  | 03  | 93.50000 |
| 01  | 80.0  | 01  | 89.66667 |
| 01  | 90.0  | 02  | 89.66667 |
| 01  | 99.0  | 03  | 89.66667 |
| 05  | 76.0  | 01  | 81.50000 |
| 05  | 87.0  | 02  | 81.50000 |
| 03  | 80.0  | 01  | 80.00000 |
| 03  | 80.0  | 02  | 80.00000 |
| 03  | 80.0  | 03  | 80.00000 |
| 02  | 70.0  | 01  | 70.00000 |
| 02  | 60.0  | 02  | 70.00000 |
| 02  | 80.0  | 03  | 70.00000 |
| 04  | 50.0  | 01  | 33.33333 |
| 04  | 30.0  | 02  | 33.33333 |
| 04  | 20.0  | 03  | 33.33333 |
| 06  | 31.0  | 01  | 32.50000 |
| 06  | 34.0  | 03  | 32.50000 |
+-----+-------+-----+----------+
18 rows in set

解析:

先求平均成績,注意,這里的平均成績一定要取別名,然后取所有人的成績,再關聯,然后按照平均成績降序排列

  15、查詢各科成績最高分、最低分和平均分

  以如下形式顯示:

  課程 id,最高分,最低分,平均分,及格率,中等率,
  優良率,優秀率
  及格為>=60,中等為:[70,80),優良為:[80-90),優秀為:>=90
  要求輸出課程號和選修人數,查詢結果按人數降序排列,若人數相同,按課程號升序

 

SELECT cid AS 課程id,MAX(score) AS 最高分,MIN(score) AS 最低分 ,AVG(score) AS 平均分, 
SUM(CASE WHEN score >=60 THEN 1 ELSE 0 END)/COUNT(sid) AS 及格率,
SUM(CASE WHEN score >=70 AND score <80 THEN 1 ELSE 0 END)/count(sid) AS 中等率,
SUM(CASE WHEN score >=80 AND score <90 THEN 1 ELSE 0 END)/count(sid) AS 優良率,
SUM(CASE WHEN score >=90 THEN 1 ELSE 0 END)/count(sid) AS 優秀率
FROM sc GROUP BY cid ORDER BY cid ASC;

結果:

+--------+--------+--------+----------+--------+--------+--------+--------+
| 課程id | 最高分 | 最低分 | 平均分   | 及格率 | 中等率 | 優良率 | 優秀率 |
+--------+--------+--------+----------+--------+--------+--------+--------+
| 01     | 80.0   | 31.0   | 64.50000 | 0.6667 | 0.3333 | 0.3333 | 0.0000 |
| 02     | 90.0   | 30.0   | 72.66667 | 0.8333 | 0.0000 | 0.5000 | 0.1667 |
| 03     | 99.0   | 20.0   | 68.50000 | 0.6667 | 0.0000 | 0.3333 | 0.3333 |
+--------+--------+--------+----------+--------+--------+--------+--------+
3 rows in set

解析:

重點在case when語句的用法,其實case when 就類似於 if函數 if x>某個值,then 1 else 0。就只用一個表,只是對表頭需要做修改,用聚合函數+AS

  16、按各科成績進行排序,並顯示排名, Score 重復時保留名次空缺

select *, rank() over(partition by cid order by score desc) AS ranked from sc;

結果:

+-----+-----+-------+--------+
| sid | cid | score | ranked |
+-----+-----+-------+--------+
| 01  | 01  | 80.0  |      1 |
| 03  | 01  | 80.0  |      1 |
| 05  | 01  | 76.0  |      3 |
| 02  | 01  | 70.0  |      4 |
| 04  | 01  | 50.0  |      5 |
| 06  | 01  | 31.0  |      6 |
| 01  | 02  | 90.0  |      1 |
| 07  | 02  | 89.0  |      2 |
| 05  | 02  | 87.0  |      3 |
| 03  | 02  | 80.0  |      4 |
| 02  | 02  | 60.0  |      5 |
| 04  | 02  | 30.0  |      6 |
| 01  | 03  | 99.0  |      1 |
| 07  | 03  | 98.0  |      2 |
| 02  | 03  | 80.0  |      3 |
| 03  | 03  | 80.0  |      3 |
| 06  | 03  | 34.0  |      5 |
| 04  | 03  | 20.0  |      6 |
+-----+-----+-------+--------+
18 rows in set

解析:

MySQL可以實現Oracle中的排名公式,一共有三種
1. rank() over(order by col_name desc)2.dense_rank() over() 3.row_number() over()
第一個是如果出現了相同排名都為同一排名,下個排名跳過,例如1,1,3,4
第二個是如果出現了相同排名都為同一排名,下個排名不跳過,例如1,1,2,3
第三個是直接對行進行排名不分是否有相同值
此題目要按照各科成績進行排序 over()中要填partition by col_name order by col_name
第一個colname 為分組的內容,第二個是按什么值排的內容

  17、查詢學生的總成績,並進行排名,總分重復時保留名次空缺

SELECT a.*,rank() over(ORDER BY a.總成績 DESC) AS Ranked  FROM
(SELECT *, SUM(score) AS 總成績 FROM sc GROUP BY sid)  AS a ;

結果:

+-----+-----+-------+--------+--------+
| sid | cid | score | 總成績 | Ranked |
+-----+-----+-------+--------+--------+
| 01  | 01  | 80.0  | 269.0  |      1 |
| 03  | 01  | 80.0  | 240.0  |      2 |
| 02  | 01  | 70.0  | 210.0  |      3 |
| 07  | 02  | 89.0  | 187.0  |      4 |
| 05  | 01  | 76.0  | 163.0  |      5 |
| 04  | 01  | 50.0  | 100.0  |      6 |
| 06  | 01  | 31.0  | 65.0   |      7 |
+-----+-----+-------+--------+--------+
7 rows in set

解析:

跟上題一樣用rank()over(),只是多了層嵌套

  18、查詢學生的總成績,並進行排名,總分重復時不保留名次空缺

SELECT a.*,dense_rank() over(ORDER BY a.total_socre DESC) AS Ranked FROM
(SELECT *,SUM(score) AS total_socre FROM sc GROUP BY sid) AS a;

結果:

+-----+-----+-------+-------------+--------+
| sid | cid | score | total_socre | Ranked |
+-----+-----+-------+-------------+--------+
| 01  | 01  | 80.0  | 269.0       |      1 |
| 03  | 01  | 80.0  | 240.0       |      2 |
| 02  | 01  | 70.0  | 210.0       |      3 |
| 07  | 02  | 89.0  | 187.0       |      4 |
| 05  | 01  | 76.0  | 163.0       |      5 |
| 04  | 01  | 50.0  | 100.0       |      6 |
| 06  | 01  | 31.0  | 65.0        |      7 |
+-----+-----+-------+-------------+--------+
7 rows in set

解析:

和上面一樣,只是換成dense_rank () over(),只是總分沒有重復無法看出區別

  19、統計各科成績各分數段人數:課程編號,[100-85),[85-70),[70-60),[60-0] 及所占百分比

SELECT cid AS 課程ID, 
SUM(CASE WHEN score <= 60 THEN 1 ELSE 0 END)/count(sid) AS 百分比1,
SUM(CASE WHEN score >60 AND score <=70 THEN 1 ELSE 0 END)/count(sid) AS 百分比2,
SUM(CASE WHEN score >70 AND score <=85 THEN 1 ELSE 0 END)/count(sid) AS 百分比3,
SUM(CASE WHEN score >85 THEN 1 ELSE 0 END)/count(sid) AS 百分比4
FROM sc GROUP BY cid ORDER BY cid

結果:

+--------+---------+---------+---------+---------+
| 課程ID | 百分比1 | 百分比2 | 百分比3 | 百分比4 |
+--------+---------+---------+---------+---------+
| 01     | 0.3333  | 0.1667  | 0.5000  | 0.0000  |
| 02     | 0.3333  | 0.0000  | 0.1667  | 0.5000  |
| 03     | 0.3333  | 0.0000  | 0.3333  | 0.3333  |
+--------+---------+---------+---------+---------+
3 rows in set

解析:

使用case when

  20、查詢各科成績前三名的記錄

SELECT * FROM
(SELECT *,rank() over(PARTITION by cid ORDER BY score desc) as ranked FROM sc) as a
WHERE a.ranked <=3;

結果:

+-----+-----+-------+--------+
| sid | cid | score | ranked |
+-----+-----+-------+--------+
| 01  | 01  | 80.0  |      1 |
| 03  | 01  | 80.0  |      1 |
| 05  | 01  | 76.0  |      3 |
| 01  | 02  | 90.0  |      1 |
| 07  | 02  | 89.0  |      2 |
| 05  | 02  | 87.0  |      3 |
| 01  | 03  | 99.0  |      1 |
| 07  | 03  | 98.0  |      2 |
| 02  | 03  | 80.0  |      3 |
| 03  | 03  | 80.0  |      3 |
+-----+-----+-------+--------+
10 rows in set

解析:

與上面rank一樣,用rank()over()where ranked <=3
注意!where 的執行順序在select前,嵌套一個select 語句就好

  21、查詢每門課程被選修的學生數

SELECT  cid AS 課程id,COUNT(sid) AS 選修的學生數 FROM sc GROUP BY cid ORDER BY 課程id;

結果:

+--------+--------------+
| 課程id | 選修的學生數 |
+--------+--------------+
| 01     |            6 |
| 02     |            6 |
| 03     |            6 |
+--------+--------------+
3 rows in set

解析:

單表 查詢,使用group by ,order by

  22、查詢出只選修兩門課程的學生學號和姓名

SELECT student.sname,a.* FROM student JOIN
(SELECT sid,count(cid) as 選修課程數 FROM sc  GROUP BY sid HAVING 選修課程數 = 2) as a ON student.sid = a.sid;

結果:

+-------+-----+------------+
| sname | sid | 選修課程數 |
+-------+-----+------------+
| 周梅  | 05  |          2 |
| 吳蘭  | 06  |          2 |
| 鄭竹  | 07  |          2 |
+-------+-----+------------+
3 rows in set

解析:

先從成績表中查詢出只選修兩門課程的學生id和課程數,再和學生表進行關聯查詢

備注:

眾所周知SQL的執行順序應該為
FORM-JOIN ON-WHERE-GROUP BY-HAVING-SELECT-DISTINCT-UNION-ORDER
但是為什么上述語句中的能夠在HAVING后面直接更SELECT語句里面的別名
因為mysql在版本迭代中,mysql對having做出了擴展,即having能夠'解析'select中的別名,但是執行順序還是having在select前。但是大多數標准SQL中,having是無法引用別名的。
還有where 后不能用聚合函數,having后可以用聚合函數

  23、查詢男生、女生人數

SELECT ssex,COUNT(sid) FROM student GROUP BY ssex;

結果:

+------+------------+
| ssex | COUNT(sid) |
+------+------------+
||          4 |
||          4 |
+------+------------+
2 rows in set

解析:

根據ssex  group by后再count()

  24、查詢名字中含有「風」字的學生信息

SELECT * FROM student WHERE sname like "%%";

結果:

+-----+-------+---------------------+------+
| sid | sname | sage                | ssex |
+-----+-------+---------------------+------+
| 03  | 孫風  | 1990-05-20 00:00:00 ||
+-----+-------+---------------------+------+
1 row in set

解析:

通配符,%,‘%a’a結尾,‘a%’a開頭,‘%a%’含有a

  25、查詢同名同性學生名單,並統計同名人數

SELECT *,COUNT(sid) as 同名人數 FROM  
(SELECT  a.* FROM student AS a JOIN student as b WHERE a.sname = b.sname AND a.ssex = b.ssex) as c  GROUP BY sid HAVING 同名人數 >=2;

結果:

 

 解析:

連接表student和student on ssname and ssex 在group by sid(因為id唯一,name可能重名),count sid

  26、查詢 1990 年出生的學生名單

SELECT * FROM student  WHERE YEAR(sage) = 1990;

結果:

+-----+-------+---------------------+------+
| sid | sname | sage                | ssex |
+-----+-------+---------------------+------+
| 01  | 趙雷  | 1990-01-01 00:00:00 ||
| 02  | 錢電  | 1990-12-21 00:00:00 ||
| 03  | 孫風  | 1990-05-20 00:00:00 ||
| 04  | 李雲  | 1990-08-06 00:00:00 ||
| 08  | 王菊  | 1990-01-20 00:00:00 ||
+-----+-------+---------------------+------+
5 rows in set

解析:

sage一列為datetime類型,用時間函數。MySQL里面能夠對datetime類型函數截取年、月、周、日等等 ,用YEAR()來表示年,以此類推

  27、查詢每門課程的平均成績,結果按平均成績降序排列,平均成績相同時,按課程編號升序排列

SELECT cid,avg(score) AS 平均成績 FROM sc GROUP BY cid ORDER BY 平均成績 DESC,cid ASC;

結果:

+-----+----------+
| cid | 平均成績 |
+-----+----------+
| 02  | 72.66667 |
| 03  | 68.50000 |
| 01  | 64.50000 |
+-----+----------+
3 rows in set

解析:

order by x desc,y,z,... 先根據x排序,再根據y,然后z....

  28、 查詢平均成績大於等於 85 的所有學生的學號、姓名和平均成績

SELECT student.sname , a.* FROM student 
JOIN
(SELECT sid as 學號, avg(score) as 平均成績 FROM sc GROUP BY sid HAVING 平均成績 > 85) as a ON student.sid = a.學號;

結果:

+-------+------+----------+
| sname | 學號 | 平均成績 |
+-------+------+----------+
| 趙雷  | 01   | 89.66667 |
| 鄭竹  | 07   | 93.50000 |
+-------+------+----------+
2 rows in set

解析:

先從成績表中查詢出平均成績大於85的學生好和平均成績(記住,這里需要取別名),然后再和學生表關聯,關聯字段為sid,獲取到學生名字

  29、查詢課程名稱為「數學」,且分數低於 60 的學生姓名和分數

SELECT  student.sname,c.* FROM student 
JOIN
(SELECT  t1.cname,t2.score,t2.sid  FROM course as t1 
JOIN sc  as t2 
ON t1.cid = t2.cid 
WHERE  t2.score < 60  AND t1.cname = "數學") as c ON student.sid = c.sid;

結果:

+-------+-------+-------+-----+
| sname | cname | score | sid |
+-------+-------+-------+-----+
| 李雲  | 數學  | 30.0  | 04  |
+-------+-------+-------+-----+
1 row in set

解析:

先把課程表和成績表關聯,獲取到低於60分的學生號、分數和課程名稱,作為臨時表,然后再和學生表關聯,獲取到最后一個字段,學生姓名

   30、查詢所有學生的課程及分數情況(存在學生沒成績,沒選課的情況)

SELECT  student.sname,c.* FROM student
JOIN
(SELECT a.cname,b.sid,b.score  FROM course as a 
LEFT JOIN
sc AS b on a.cid = b.cid) as c on student.sid = c.sid;

結果:

+-------+-------+-----+-------+
| sname | cname | sid | score |
+-------+-------+-----+-------+
| 趙雷  | 語文  | 01  | 80.0  |
| 趙雷  | 數學  | 01  | 90.0  |
| 趙雷  | 英語  | 01  | 99.0  |
| 錢電  | 語文  | 02  | 70.0  |
| 錢電  | 數學  | 02  | 60.0  |
| 錢電  | 英語  | 02  | 80.0  |
| 孫風  | 語文  | 03  | 80.0  |
| 孫風  | 數學  | 03  | 80.0  |
| 孫風  | 英語  | 03  | 80.0  |
| 李雲  | 語文  | 04  | 50.0  |
| 李雲  | 數學  | 04  | 30.0  |
| 李雲  | 英語  | 04  | 20.0  |
| 周梅  | 語文  | 05  | 76.0  |
| 周梅  | 數學  | 05  | 87.0  |
| 吳蘭  | 語文  | 06  | 31.0  |
| 吳蘭  | 英語  | 06  | 34.0  |
| 鄭竹  | 數學  | 07  | 89.0  |
| 鄭竹  | 英語  | 07  | 98.0  |
+-------+-------+-----+-------+
18 rows in set

解析:

先把課程表和成績表關聯,關聯字段為cid,獲取到課程名稱,學生號和學科成績,作為臨時表,然后再和學生表關聯,關聯字段為sid,獲取到學生名字

  31、查詢任何一門課程成績在 70 分以上的姓名、課程名稱和分數

SELECT  student.sname,c.* FROM student
JOIN
(SELECT a.cname,b.sid,b.score  FROM course as a 
LEFT JOIN
sc AS b on a.cid = b.cid) as c on student.sid = c.sid WHERE c.score > 70;

結果:

+-------+-------+-----+-------+
| sname | cname | sid | score |
+-------+-------+-----+-------+
| 趙雷  | 語文  | 01  | 80.0  |
| 趙雷  | 數學  | 01  | 90.0  |
| 趙雷  | 英語  | 01  | 99.0  |
| 錢電  | 英語  | 02  | 80.0  |
| 孫風  | 語文  | 03  | 80.0  |
| 孫風  | 數學  | 03  | 80.0  |
| 孫風  | 英語  | 03  | 80.0  |
| 周梅  | 語文  | 05  | 76.0  |
| 周梅  | 數學  | 05  | 87.0  |
| 鄭竹  | 數學  | 07  | 89.0  |
| 鄭竹  | 英語  | 07  | 98.0  |
+-------+-------+-----+-------+
11 rows in set

解析:

在上一題的基礎上增加score > 70,使用where 或and都可以

  32、查詢不及格的課程

SELECT cname,a.* FROM course 
JOIN
(SELECT score,cid FROM sc WHERE score < 60) as a
ON course.cid = a.cid;

結果:

+-------+-------+-----+
| cname | score | cid |
+-------+-------+-----+
| 語文  | 50.0  | 01  |
| 數學  | 30.0  | 02  |
| 英語  | 20.0  | 03  |
| 語文  | 31.0  | 01  |
| 英語  | 34.0  | 03  |
+-------+-------+-----+
5 rows in set

解析:

先從成績表中獲取到不及格的課程id和成績,然后再和課程表關聯,關聯字典為課程id,獲取到課程名稱

  33、查詢課程編號為 01 且課程成績在 60 分以上的學生的學號和姓名

SELECT student.sname,c.* FROM student 
JOIN
(SELECT  b.sid ,b.score,a.cid ,a.cname FROM course as a
JOIN
sc as b
ON a.cid = b.cid WHERE a.cid = "01" AND b.score > 60) as c  ON student.sid = c.sid;

結果:

+-------+-----+-------+-----+-------+
| sname | sid | score | cid | cname |
+-------+-----+-------+-----+-------+
| 趙雷  | 01  | 80.0  | 01  | 語文  |
| 錢電  | 02  | 70.0  | 01  | 語文  |
| 孫風  | 03  | 80.0  | 01  | 語文  |
| 周梅  | 05  | 76.0  | 01  | 語文  |
+-------+-----+-------+-----+-------+
4 rows in set

解析:

先從課程表和成績表中獲取到學生號、成績、課程號和課程名稱,關聯字段為課程號,作為臨時表,然后再和學生表關聯,關聯字段為學生號,獲取到學生名字

  34、求每門課程的學生人數

SELECT course.cname,a.* FROM course 
JOIN
(SELECT   count(sid),cid FROM sc  GROUP BY cid) as a ON course.cid = a.cid;

結果:

+-------+------------+-----+
| cname | count(sid) | cid |
+-------+------------+-----+
| 語文  |          6 | 01  |
| 數學  |          6 | 02  |
| 英語  |          6 | 03  |
+-------+------------+-----+
3 rows in set

解析:

先從成績表中統計出每門課程的人數,再和課程表關聯,關聯字段為課程號,獲取到課程名稱

  35、成績沒有重復的情況下,查詢選修「張三」老師所授課程的學生中,成績最高的學生信息及其成績

SELECT student.sname ,e.* FROM student 
JOIN
(SELECT MAX(d.score),c.* ,d.sid FROM sc AS d
JOIN
(SELECT a.tid,a.tname,b.cid,b.cname FROM teacher AS a
JOIN
course AS b ON a.tid = b.tid WHERE a.tname = "張三") as c ON d.cid = c.cid) as e ON student.sid = e.sid;

結果:

+-------+--------------+-----+-------+-----+-------+-----+
| sname | MAX(d.score) | tid | tname | cid | cname | sid |
+-------+--------------+-----+-------+-----+-------+-----+
| 趙雷  | 90.0         | 01  | 張三  | 02  | 數學  | 01  |
+-------+--------------+-----+-------+-----+-------+-----+
1 row in set

解析:

教師表和課程表關聯,獲取到教師編號、教師名稱和課程編號和課程名稱,關聯字段為教師編號

作為臨時表再和成績表關聯,關聯字段為課程編號

作為臨時表再和學生表關聯,關聯字段為學生號

  36、成績有重復的情況下,查詢選修「張三」老師所授課程的學生中,成績最高的學生信息及其成績

SELECT student.sname ,e.*  FROM student 
JOIN
(SELECT MAX(d.score),c.* ,d.sid,rank() over(ORDER BY MAX(d.score))as Ranked FROM sc AS d
JOIN
(SELECT a.tid,a.tname,b.cid,b.cname FROM teacher AS a
JOIN
course AS b ON a.tid = b.tid WHERE a.tname = "張三") as c ON d.cid = c.cid) as e ON student.sid = e.sid WHERE e.Ranked ;

結果:

+-------+--------------+-----+-------+-----+-------+-----+--------+
| sname | MAX(d.score) | tid | tname | cid | cname | sid | Ranked |
+-------+--------------+-----+-------+-----+-------+-----+--------+
| 趙雷  | 90.0         | 01  | 張三  | 02  | 數學  | 01  |      1 |
+-------+--------------+-----+-------+-----+-------+-----+--------+
1 row in set

解析:

用rank函數,然后再嵌套一個select,where rank = 1

  37、查詢不同課程成績相同的學生的學生編號、課程編號、學生成績

SELECT DISTINCT a.* FROM sc AS a
    JOIN sc AS b
        ON a.score =b.score AND a.cid != b.cid 

結果:

+-----+-----+-------+
| sid | cid | score |
+-----+-----+-------+
| 02  | 03  | 80.0  |
| 03  | 02  | 80.0  |
| 03  | 03  | 80.0  |
| 01  | 01  | 80.0  |
| 03  | 01  | 80.0  |
+-----+-----+-------+
5 rows in set

解析:

sc表自連,distinct去重,cid 不同,score相同

  38、查詢每門功成績最好的前兩名

SELECT * FROM
    (SELECT *,dense_rank()over(PARTITION BY cid ORDER BY score DESC) AS ranked FROM sc ) a
WHERE a.ranked <=2

結果:

+-----+-----+-------+--------+
| sid | cid | score | ranked |
+-----+-----+-------+--------+
| 01  | 01  | 80.0  |      1 |
| 03  | 01  | 80.0  |      1 |
| 05  | 01  | 76.0  |      2 |
| 01  | 02  | 90.0  |      1 |
| 07  | 02  | 89.0  |      2 |
| 01  | 03  | 99.0  |      1 |
| 07  | 03  | 98.0  |      2 |
+-----+-----+-------+--------+
7 rows in set

解析:

我認為最好的前兩名是排名的前2個,即第一個排名1 和第二個排名2,如果有兩個並列第一,一個第二,那么前兩名應該是3個人,用dense_rank,排名不跳過;如果說是最好的前兩個人,就用rank,排名跳過

  39、統計每門課程的學生選修人數(超過 5 人的課程才統計)

SELECT  course.cname,a.* FROM course 
JOIN
(SELECT  cid,COUNT(sid) as 選修人數 FROM sc GROUP BY cid HAVING COUNT(sid) >5) as a
ON course.cid = a.cid;

結果:

+-------+-----+----------+
| cname | cid | 選修人數 |
+-------+-----+----------+
| 語文  | 01  |        6 |
| 數學  | 02  |        6 |
| 英語  | 03  |        6 |
+-------+-----+----------+
3 rows in set

解析:

group by,having聚合

  40、檢索至少選修兩門課程的學生學號

SELECT  student.sname,a.* FROM student
JOIN
(SELECT  sid,COUNT(cid) as 選修課程總數 FROM sc GROUP BY sid HAVING 選修課程總數 >=2) as a on student.sid = a.sid;

結果:

+-------+-----+--------------+
| sname | sid | 選修課程總數 |
+-------+-----+--------------+
| 趙雷  | 01  |            3 |
| 錢電  | 02  |            3 |
| 孫風  | 03  |            3 |
| 李雲  | 04  |            3 |
| 周梅  | 05  |            2 |
| 吳蘭  | 06  |            2 |
| 鄭竹  | 07  |            2 |
+-------+-----+--------------+
7 rows in set

解析:

 

  41、查詢選修了全部課程的學生信息

SELECT  student.*,c.`選修課程總數` from student 
JOIN
(SELECT b.sid,COUNT(a.cid) as 選修課程總數 FROM course a 
JOIN
sc b  ON a.cid = b.cid GROUP BY b.sid HAVING COUNT(a.cid) = (SELECT COUNT(cid) FROM course)) as c ON student.sid = c.sid;

結果:

+-----+-------+---------------------+------+--------------+
| sid | sname | sage                | ssex | 選修課程總數 |
+-----+-------+---------------------+------+--------------+
| 01  | 趙雷  | 1990-01-01 00:00:00 ||            3 |
| 02  | 錢電  | 1990-12-21 00:00:00 ||            3 |
| 03  | 孫風  | 1990-05-20 00:00:00 ||            3 |
| 04  | 李雲  | 1990-08-06 00:00:00 ||            3 |
+-----+-------+---------------------+------+--------------+
4 rows in set

解析:

從課程表中查詢出總的課程數,作為后面子查詢的條件

從成績表中查詢出選修了全部課程數的的學生號和選修的課程總數

作為臨時表和學生表關聯,關聯字段為學生號,獲取到全部的學生信息

   42、查詢各學生的年齡,只按年份來算

SELECT  sname,YEAR(NOW()) - YEAR(sage) as 年齡 FROM student;

結果:

+-------+------+
| sname | 年齡 |
+-------+------+
| 趙雷  |   31 |
| 錢電  |   31 |
| 孫風  |   31 |
| 李雲  |   31 |
| 周梅  |   30 |
| 吳蘭  |   29 |
| 鄭竹  |   32 |
| 王菊  |   31 |
+-------+------+
8 rows in set

解析:

使用year函數

  43、按照出生日期來算,當前月日 < 出生年月的月日則,年齡減一

SELECT sname,
   CASE 
    WHEN (DATE_FORMAT(NOW(),'%m-%d') - DATE_FORMAT(sage,'%m-%d')) < 0 
        THEN YEAR(NOW()) - YEAR(sage) - 1
        ELSE YEAR(NOW()) - YEAR(sage)
    END AS age
FROM student;

結果:

+-------+-----+
| sname | age |
+-------+-----+
| 趙雷  |  31 |
| 錢電  |  30 |
| 孫風  |  31 |
| 李雲  |  31 |
| 周梅  |  29 |
| 吳蘭  |  29 |
| 鄭竹  |  32 |
| 王菊  |  31 |
+-------+-----+
8 rows in set

解析:

有兩種方法,一種是利用date_format直接截取時間類型中的月日,直接比大小
另外一種是用month()先比大小,相等再用day()比大小

  44、查詢本周過生日的學生

SELECT sname FROM student  WHERE week(NOW()) = WEEK(sage);

結果:

Empty set

解析:

week() 返回的是今年的第幾周,即如果本周過生,返回數字相等

  45、查詢下周過生日的學生

SELECT sname FROM student  WHERE week(NOW()) + 1 = WEEK(sage);

結果:

Empty set

解析:

加一就行

  46、查詢本月過生日的學生

SELECT sname FROM student  WHERE month(NOW()) = month(sage);

結果:

Empty set

解析:

使用month函數

  47、查詢下月過生日的學生

SELECT sname FROM student  WHERE month(NOW()) + 1 = month(sage);

結果:

Empty set

解析:

加一即可

  48、49、50是刪除的,這里就不羅列


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM