一、環境准備
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是刪除的,這里就不羅列