數據結構說明
已知有如下4張表:
學生表:student(學號,學生姓名,出生年月,性別)
成績表:score(學號,課程號,成績)
課程表:course(課程號,課程名稱,教師號)
教師表:teacher(教師號,教師姓名)
准備練習數據
1)創建學生表(student)
CREATE TABLE `student` (
`學號` varchar(255) NOT NULL,
`姓名` varchar(50) DEFAULT NULL,
`出生日期` date DEFAULT NULL,
`性別` varchar(10) DEFAULT NULL,
PRIMARY KEY (`學號`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2)創建成績表(score)
CREATE TABLE `score` (
`學號` varchar(255) NOT NULL,
`課程號` varchar(255) NOT NULL,
`成績` float(3,0) DEFAULT NULL,
PRIMARY KEY (`學號`,`課程號`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3)創建課程表(course)
CREATE TABLE `course` (
`課程號` varchar(255) NOT NULL,
`課程名稱` varchar(255) DEFAULT NULL,
`教師號` varchar(255) DEFAULT NULL,
PRIMARY KEY (`課程號`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4)教師表(teacher)
CREATE TABLE `teacher` (
`教師號` varchar(255) NOT NULL,
`教師姓名` varchar(50) DEFAULT NULL,
PRIMARY KEY (`教師號`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1)學生表添加數據
insert into student(學號,姓名,出生日期,性別)
values('0001' , '猴子' , '1989-01-01' , '男');
insert into student(學號,姓名,出生日期,性別)
values('0002' , '猴子' , '1990-12-21' , '女');
insert into student(學號,姓名,出生日期,性別)
values('0003' , '馬雲' , '1991-12-21' , '男');
insert into student(學號,姓名,出生日期,性別)
values('0004' , '王思聰' , '1990-05-20' , '男');
2)成績表添加數據
insert into score(學號,課程號,成績)
values('0001' , '0001' , 80);
insert into score(學號,課程號,成績)
values('0001' , '0002' , 90);
insert into score(學號,課程號,成績)
values('0001' , '0003' , 99);
insert into score(學號,課程號,成績)
values('0002' , '0002' , 60);
insert into score(學號,課程號,成績)
values('0002' , '0003' , 80);
insert into score(學號,課程號,成績)
values('0003' , '0001' , 80);
insert into score(學號,課程號,成績)
values('0003' , '0002' , 80);
insert into score(學號,課程號,成績)
values('0003' , '0003' , 80);
3)課程表添加數據
insert into course(課程號,課程名稱,教師號)
values('0001' , '語文' , '0002');
insert into course(課程號,課程名稱,教師號)
values('0002' , '數學' , '0001');
insert into course(課程號,課程名稱,教師號)
values('0003' , '英語' , '0003');
4)教師表添加數據
-- 教師表:添加數據
insert into teacher(教師號,教師姓名)
values('0001' , '孟扎扎');
insert into teacher(教師號,教師姓名)
values('0002' , '馬化騰');
-- 這里的教師姓名是空值(null)
insert into teacher(教師號,教師姓名)
values('0003' , null);
-- 這里的教師姓名是空字符串('')
insert into teacher(教師號,教師姓名)
values('0004' , '');
簡單查詢
-
查詢姓“猴”的學生名單
SELECT * FROM student WHERE 姓名 LIKE '猴%';
-
查詢姓名中最后一個字是“猴”字的學生名單
SELECT * FROM student WHERE 姓名 LIKE '%猴';
-
查詢姓名中帶“猴”字的學生名單
SELECT * FROM student WHERE 姓名 LIKE '%猴%';
- 查詢姓“孟”老師的個數
SELECT COUNT(教師號) FROM teacher WHERE 教師姓名 LIKE '孟%';
匯總分析
1.匯總分析
- 查詢課程編號為“0002”的總成績
*
分析思路
select 查詢結果 [總成績:匯總函數sum]
from 從哪張表中查找數據[成績表score]
where 查詢條件 [課程號是0002]
*/
SELECT SUM(成績) FROM score WHERE 課程號='0002';
- 查詢選了課程的學生人數
/*
這個題目翻譯成大白話就是:查詢有多少人選了課程
select 學號,成績表里學號有重復值需要去掉
from 從課程表查找score;
*/
SELECT COUNT(DISTINCT 學號) 選了課程的學生人數 FROM score;
2.分組
- 查詢各科成績的最高分和最低分, 以如下的形式顯示:課程號,最高分,最低分
/*
分析思路
select 查詢結果 [課程ID:是課程號的別名,最高分:max(成績) ,最低分:min(成績)]
from 從哪張表中查找數據 [成績表score]
where 查詢條件 [沒有]
group by 分組 [各科成績:也就是每門課程的成績,需要按課程號分組]
having 分組后過濾[沒有]
order by 排序desc、asc[沒有]
limit 分頁和限制數量[沒有];
*/
SELECT 課程號,MAX(成績) 最高分,MIN(成績) 最低分
FROM score
GROUP BY 課程號; -- 是先分組再查詢每組得最高分和最低分
- 查詢每門課程選修的學生數
SELECT 課程號,COUNT(學號) 選修學生人數
FROM score
GROUP BY 課程號;
- 查詢男生、女生人數
SELECT 性別,COUNT(學號) 總人數
FROM student
GROUP BY 性別;
3.分組結果的條件
- 查詢平均成績大於60分學生的學號和平均成績
SELECT 學號,AVG(成績) 平均成績
FROM score
GROUP BY 學號
HAVING AVG(成績)>60;
- 查詢至少選修兩門課程的學生學號
SELECT 學號,COUNT(課程號) 選修課程數量
FROM score
GROUP BY 學號
HAVING COUNT(課程號)>=2;
- 查詢同名同姓學生名單並統計同名人數
分析:條件:怎么算姓名相同?按姓名分組后人數大於等於2,因為同名的人數大於等於2,分析出這一點很重要
SELECT 姓名,COUNT(*)
FROM student
GROUP BY 姓名
HAVING COUNT(*)>=2;
- 查詢不及格的課程並按課程號從大到小排列
SELECT 課程號
FROM score
WHERE 成績<60
ORDER BY 課程號 DESC;
- 查詢每門課程的平均成績,結果按平均成績升序排序,平均成績相同時,按課程號降序排列
SELECT 課程號,AVG(成績) 平均成績
FROM score
GROUP BY 課程號
ORDER BY 平均成績 ASC,課程號 DESC;
- 檢索課程編號為“0004”且分數小於60的學生學號,結果按按分數降序排列
from score
WHERE 課程號='0004' AND 成績<60
ORDER BY 成績 DESC;
- 統計每門課程的學生選修人數(超過2人的課程才統計),要求輸出課程號和選修人數,查詢結果按人數降序排序,若人數相同,按課程號升序排序
SELECT 課程號,COUNT(學號) 選修人數
FROM score
GROUP BY 課程號
HAVING COUNT(學號)>2
ORDER BY COUNT(學號) DESC,課程號 ASC;
- 查詢兩門以上不及格課程的同學的學號及其平均成績
/*
分析思路
先分解題目:
1)[兩門以上][不及格課程]限制條件
2)[同學的學號及其平均成績],也就是每個學生的平均成績,顯示學號,平均成績
分析過程:
第1步:得到每個學生的平均成績,顯示學號,平均成績
第2步:再加上限制條件:
1)不及格課程
2)兩門以上[不及格課程]:課程數目>2
/*
第1步:得到每個學生的平均成績,顯示學號,平均成績
select 查詢結果 [學號,平均成績:匯總函數avg(成績)]
from 從哪張表中查找數據 [涉及到成績:成績表score]
where 查詢條件 [沒有]
group by 分組 [每個學生的平均:按學號分組]
having 對分組結果指定條件 [沒有]
order by 對查詢結果排序[沒有];
*/
select 學號, avg(成績) as 平均成績
from score
group by 學號;
/*
第2步:再加上限制條件:
1)不及格課程
2)兩門以上[不及格課程]
select 查詢結果 [學號,平均成績:匯總函數avg(成績)]
from 從哪張表中查找數據 [涉及到成績:成績表score]
where 查詢條件 [限制條件:不及格課程,平均成績<60]
group by 分組 [每個學生的平均:按學號分組]
having 對分組結果指定條件 [限制條件:課程數目>2,匯總函數count(課程號)>2]
order by 對查詢結果排序[沒有];
*/
SELECT 學號,AVG(成績) 平均成績 -- **這是小於60分課程的平均成績,按題目理解是要查詢這個學生全部課程的平均成績**
FROM score
where 成績<60
GROUP BY 學號
HAVING COUNT(課程號)>=2;
4.查詢結構排序,分組的指定條件
- 查詢學生的總成績並進行排名
SELECT 學號,SUM(成績) 總成績
from score
GROUP BY 學號
ORDER BY 總成績;
- 查詢平均成績大於60分的學生的學號和平均成績
SELECT 學號,AVG(成績) 平均成績
FROM score
GROUP BY 學號
HAVING 平均成績>60;
復雜查詢
- 查詢課程成績小於60分學生的學號、姓名
【知識點】子查詢
1.翻譯成大白話
1)查詢結果:學生學號,姓名
2)查詢條件:所有課程成績 < 60 的學生,需要從成績表里查找,用到子查詢
第1步,寫子查詢(所有課程成績 < 60 的學生)
select 查詢結果[學號]
from 從哪張表中查找數據[成績表:score]
where 查詢條件[成績 < 60]
group by 分組[沒有]
having 對分組結果指定條件[沒有]
order by 對查詢結果排序[沒有]
limit 從查詢結果中取出指定行[沒有];
select 學號
from student
where 成績 < 60;
第2步,查詢結果:學生學號,姓名,條件是前面1步查到的學號
select 查詢結果[學號,姓名]
from 從哪張表中查找數據[學生表:student]
where 查詢條件[用到運算符in]
group by 分組[沒有]
having 對分組結果指定條件[沒有]
order by 對查詢結果排序[沒有]
limit 從查詢結果中取出指定行[沒有];
*/
SELECT 學號,姓名
FROM student
WHERE 學號 IN(SELECT 學號 from score WHERE 成績<60);
- 查詢沒有學全所有課的學生的學號、姓名
/*
查找出學號,條件:沒有學全所有課,也就是該學生選修的課程數 < 總的課程數
【考察知識點】in,子查詢
*/
SELECT 學號
FROM score
GROUP BY 學號
HAVING COUNT(課程號)<3;
SELECT 學號,姓名
FROM student WHERE 學號 IN(SELECT 學號 FROM score GROUP BY 學號 HAVING COUNT(課程號)<3);
- 查詢出只選修了兩門課程的全部學生的學號和姓名
SELECT 學號,姓名
FROM student WHERE 學號 IN(SELECT 學號 FROM score GROUP BY 學號 HAVING COUNT(課程號)=2);
日期函數
- 查找1990年出生的學生名單
/*
查找1990年出生的學生名單
學生表中出生日期列的類型是datetime
*/
SELECT * FROM student WHERE YEAR(出生日期)='1990';
- 查詢各學生的年齡(精確到月份)
/*
【知識點】時間格式轉化
*/
select 學號 ,timestampdiff(month ,出生日期 ,now())/12
from student ;
- 查詢本月過生日的學生
select *
from student
where month (出生日期 ) = month(now())+2;
top-N查詢
工作中會經常遇到這樣的業務問題:
如何找到每個類別下用戶最喜歡的產品是哪個?
如果找到每個類別下用戶點擊最多的5個商品是什么?
這類問題其實就是常見的:分組取每組最大值、最小值,每組最大的N條(top N)記錄。
- 分組取每組最大值,按課程號分組取成績最大值所在行的數據
-- 可以使用關聯子查詢來實現:
select *
from score as a
where 成績 = (
select max(成績)
from score as b
where b.課程號 = a.課程號);
- 分組取每組最小值,按課程號分組取成績最小值所在行的數據
select *
from score as a
where 成績 = (
select min(成績)
from score as b
where b.課程號 = a.課程號);
- 每組最大的N條記錄,查詢各科成績前兩名的記錄
第1步,查出有哪些組
我們可以按課程號分組,查詢出有哪些組,對應這個問題里就是有哪些課程號
select 課程號,max(成績) as 最大成績
from score
group by 課程號;
第2步:先使用order by子句按成績降序排序(desc),然后使用limt子句返回topN(對應這個問題返回的成績前兩名)
-- 課程號'0001' 這一組里成績前2名
select *
from score
where 課程號 = '0001'
order by 成績 desc
limit 2;
同樣的,可以寫出其他組的(其他課程號)取出成績前2名的sql
第3步,使用union all 將每組選出的數據合並到一起
(select * from score where 課程號 = '0001' order by 成績 desc limit 2)
union all
(select * from score where 課程號 = '0002' order by 成績 desc limit 2)
union all
(select * from score where 課程號 = '0003' order by 成績 desc limit 2);
多表查詢
- 查詢所有學生的學號、姓名、選課數、總成績
selecta.學號,a.姓名,count(b.課程號) as 選課數,sum(b.成績) as 總成績
from student as a left join score as b
on a.學號 = b.學號
group by a.學號;
- 查詢平均成績大於85的所有學生的學號、姓名和平均成績
select a.學號,a.姓名, avg(b.成績) as 平均成績
from student as a left join score as b
on a.學號 = b.學號
group by a.學號
having avg(b.成績)>85;
- 查詢學生的選課情況:學號,姓名,課程號,課程名稱
select a.學號, a.姓名, c.課程號,c.課程名稱
from student a inner join score b on a.學號=b.學號
inner join course c on b.課程號=c.課程號;
多表查詢需要掌握內連接查詢與外連接查詢,參考:
一文讓你徹底理解SQL連接查詢:https://www.cnblogs.com/Uni-Hoang/p/13246587.html
SQL高級功能:窗口函數
暫時延后