參考資料來源于Bilibili《一天學會MYSQL數據庫》
1、多表查詢
(1)查詢所有學生的s_name,c_no和grade列
由數據可知,s_name在student表,c_no和grade在score表,那么我們要考慮如何將兩個表聯立起來。
student表中的s_no和score表中的s_no通過外鍵聯系在一起。因此我們采用以下的方法:
select s_name,c_no,grade from student,score where student.s_no = score.s_no;
--result
+--------+-------+-------+
| s_name | c_no | grade |
+--------+-------+-------+
| 王麗 | 3-105 | 92 |
| 王麗 | 3-245 | 86 |
| 王麗 | 6-166 | 85 |
| 王芳 | 3-105 | 88 |
| 王芳 | 3-245 | 75 |
| 王芳 | 6-166 | 79 |
| 趙鐵柱 | 3-105 | 76 |
| 趙鐵柱 | 3-245 | 68 |
| 趙鐵柱 | 6-166 | 81 |
+--------+-------+-------+
(2)查詢所有學生的 s_name, c_name, grade列
三表聯查
select s_name, c_name, grade from student,course,score where student.s_no=score.s_no and course.c_no=score.c_no;
--result
+--------+------------+-------+
| s_name | c_name | grade |
+--------+------------+-------+
| 王麗 | 計算機導論 | 92 |
| 王麗 | 操作系統 | 86 |
| 王麗 | 數字電路 | 85 |
| 王芳 | 計算機導論 | 88 |
| 王芳 | 操作系統 | 75 |
| 王芳 | 數字電路 | 79 |
| 趙鐵柱 | 計算機導論 | 76 |
| 趙鐵柱 | 操作系統 | 68 |
| 趙鐵柱 | 數字電路 | 81 |
+--------+------------+-------+
由下面的查詢結果可知上述語句的含義是查詢了三個表中共同字段相等的記錄。
select s_name, c_name, grade,student.s_no as stu_sno, score.s_no as sco_sno
from student,course,score
where student.s_no=score.s_no and course.c_no=score.c_no;
--result
+--------+------------+-------+---------+---------+
| s_name | c_name | grade | stu_sno | sco_sno |
+--------+------------+-------+---------+---------+
| 王麗 | 計算機導論 | 92 | 103 | 103 |
| 王麗 | 操作系統 | 86 | 103 | 103 |
| 王麗 | 數字電路 | 85 | 103 | 103 |
| 王芳 | 計算機導論 | 88 | 105 | 105 |
| 王芳 | 操作系統 | 75 | 105 | 105 |
| 王芳 | 數字電路 | 79 | 105 | 105 |
| 趙鐵柱 | 計算機導論 | 76 | 109 | 109 |
| 趙鐵柱 | 操作系統 | 68 | 109 | 109 |
| 趙鐵柱 | 數字電路 | 81 | 109 | 109 |
+--------+------------+-------+---------+---------+
(3)查詢"男"教師 及其所上的課
select t.t_name, c.c_no, c.c_name from teacher as t, course as c where t_sex = '男' and t.t_no = c.t_no;
-- result
+--------+-------+----------+
| t_name | c_no | c_name |
+--------+-------+----------+
| 李誠 | 3-245 | 操作系統 |
| 張旭 | 6-166 | 數字電路 |
+--------+-------+----------+
(4)按照等級進行查詢
首先新建grade_table表,將分數的等級放進去;
CREATE TABLE grade_table(
low INT(3),
upp INT(3),
grade CHAR(1));
INSERT INTO grade VALUES(90,100,'A');
INSERT INTO grade VALUES(80,89,'B');
INSERT INTO grade VALUES(70,79,'c');
INSERT INTO grade VALUES(60,69,'D');
INSERT INTO grade VALUES(0,59,'E');
查詢所有同學的s_no , c_no 和等級列
select s_no, c_no, grade_table.grade from score, grade_table
where score.grade between low and upp;
-- result
+------+-------+-------+
| s_no | c_no | grade |
+------+-------+-------+
| 101 | 3-105 | A |
| 102 | 3-105 | A |
| 103 | 3-105 | A |
| 103 | 3-245 | B |
| 103 | 6-166 | B |
| 104 | 3-105 | B |
| 105 | 3-105 | B |
| 105 | 3-245 | C |
| 105 | 6-166 | C |
| 109 | 3-105 | C |
| 109 | 3-245 | D |
| 109 | 6-166 | B |
+------+-------+-------+
總結:
- select 在同時查詢兩個表時,如果兩個表中有相同的字段,要在字段前加入表名;
2.select同時查詢兩個表時,返回的結果是兩個表結果的笛卡爾積。上述的where在這個笛卡爾積中進行條件過濾,返回符合條件的記錄。
2、子查詢
(1)查詢班級是'95031'班學生每門課的平均分
涉及到的表:student表,score表
首先將班級為“95031”的學生信息提出,再按照課程進行分組求平均數
select * from student where s_class='95031';
-- 我們將其中的s_no數據提出作為查詢score表時的條件
select * from score where s_no in (select s_no from student where s_class='95031');
+------+-------+-------+
| s_no | c_no | grade |
+------+-------+-------+
| 105 | 3-105 | 88 |
| 105 | 3-245 | 75 |
| 105 | 6-166 | 79 |
| 109 | 3-105 | 76 |
| 109 | 3-245 | 68 |
| 109 | 6-166 | 81 |
+------+-------+-------+
--對其進行分組求平均
select c_no,avg(grade) from score where s_no in (select s_no from student where s_class='95031') group by c_no;
--result
+-------+------------+
| c_no | avg(grade) |
+-------+------------+
| 3-105 | 82.0000 |
| 3-245 | 71.5000 |
| 6-166 | 80.0000 |
+-------+------------+
(2)查詢選修"3-105"課程的成績高于'109'號同學'3-105'成績 的所有同學的記錄
select * from score
where c_no='3-105' and
grade > ( select grade from score where s_no='109' and c_no='3-105');
(3) 查詢所有學號為108.101的同學同年出生的所有學生的s_no,s_name和s_birthday
用到的函數:year()函數提取日期類型數據中的年份
select s_no,s_name from student
where year(s_birth) in (select year(s_birth)
from student where s_no in('108', '101'));
--result
+------+--------+
| s_no | s_name |
+------+--------+
| 101 | 曾華 |
| 102 | 匡明 |
| 105 | 王芳 |
| 108 | 張全蛋 |
+------+--------+
(4)查詢教師張旭所任課程的學生成績
select * from score where s_no in
(select s_no from score where c_no =
(select c_no from course
where t_no = (select t_no from teacher where t_name='張旭')));
(5)查詢選修某課程的同學人數多于5人的教師姓名
首先向數據表中添加數據
INSERT INTO score VALUES('101','3-105','90');
INSERT INTO score VALUES('102','3-105','91');
INSERT INTO score VALUES('104','3-105','89');
查詢:
select t_name from teacher where t_no in (select t_no from course
where c_no in (select c_no from score group by c_no having count(*) > 5));
進行分組后才可以統計數量;
(6) 查詢95033班和95031班全體學生的記錄
select * from student where s_class in ('95033','95031');
--result
+------+--------+-------+---------------------+---------+
| s_no | s_name | s_sex | s_birth | s_class |
+------+--------+-------+---------------------+---------+
| 101 | 曾華 | 男 | 1977-09-01 00:00:00 | 95033 |
| 102 | 匡明 | 男 | 1975-10-02 00:00:00 | 95031 |
| 103 | 王麗 | 女 | 1976-01-23 00:00:00 | 95033 |
| 104 | 李軍 | 男 | 1976-02-20 00:00:00 | 95033 |
| 105 | 王芳 | 女 | 1975-02-10 00:00:00 | 95031 |
| 106 | 陸軍 | 男 | 1974-06-03 00:00:00 | 95031 |
| 107 | 王尼瑪 | 男 | 1976-02-20 00:00:00 | 95033 |
| 108 | 張全蛋 | 男 | 1975-02-10 00:00:00 | 95031 |
| 109 | 趙鐵柱 | 男 | 1974-06-03 00:00:00 | 95031 |
+------+--------+-------+---------------------+---------+
(7) 查出所有'計算機系' 教師所教課程的成績表
select * from score
where c_no in (select c_no from course
where t_no in (select t_no from teacher where t_depart= '計算機系'));
--result
+------+-------+-------+
| s_no | c_no | grade |
+------+-------+-------+
| 103 | 3-245 | 86 |
| 105 | 3-245 | 75 |
| 109 | 3-245 | 68 |
| 101 | 3-105 | 90 |
| 102 | 3-105 | 91 |
| 103 | 3-105 | 92 |
| 104 | 3-105 | 89 |
| 105 | 3-105 | 88 |
| 109 | 3-105 | 76 |
+------+-------+-------+
(8)查詢所有任課教師的t_name 和 t_depart(注意是任課的)
select t_name, t_depart from teacher
where t_no in (select t_no from course where c_no in (select c_no from score group by c_no));
-- result
+--------+------------+
| t_name | t_depart |
+--------+------------+
| 李誠 | 計算機系 |
| 王萍 | 計算機系 |
| 張旭 | 電子工程系 |
+--------+------------+
3.UNION和NOT IN的使用
語法:UNION 操作符用于連接兩個以上的 SELECT 語句的結果組合到一個結果集合中。多個 SELECT 語句會刪除重復的數據。如果要使得數據不重復,需要使用UNION ALL。
(1) 查詢'計算機系'與'電子工程系' 不同職稱的教師的name和rof
含義:除了在計算機系和電子工程系中同時出現的職稱的所有記錄
select t_name,t_prof from teacher where t_depart = '計算機系'
and t_prof not in (select t_prof from teacher where t_depart ='電子工程系')
union
select t_name,t_prof from teacher where t_depart = '電子工程系'
and t_prof not in (select t_prof from teacher where t_depart = '計算機系');
--result
+--------+--------+
| t_name | t_prof |
+--------+--------+
| 李誠 | 副教授 |
| 張旭 | 講師 |
+--------+--------+
4.ANY和ALL的使用
(1) 查詢選修編號為"3-105"課程且成績至少高于選修編號為'3-245'同學的c_no,s_no和grade,并且按照grade從高到低次序排序
select * from score where c_no = '3-105'
and grade > (select min(grade) from score where c_no = '3-245') order by grade desc;
題中提到“至少高于”,因此也可以用any表示,any(數據集)表示其中至少一個。
select * from score where c_no = '3-105'
and grade > any(select grade from score where c_no = '3-245') order by grade desc;
(2)查詢選修編號為"3-105"且成績高于選修編號為"3-245"課程的同學c_no.s_no和grade
select * from score where c_no = '3-105'
and grade > (select max(grade) from score where c_no = '3-245') order by grade desc;
也可以用all表示:
select * from score where c_no = '3-105'
and grade > all (select grade from score where c_no = '3-245') order by grade desc;
總結: ANY 和 ALL
ANY:表示比任何一個就行了。
ALL:表示所有都要比較。
5.別名的使用
規則:
a. select 字段名 as 別名。
b. 當兩個表連接時,union后的表列名與第一個表保持一致。
select t_name as name, t_sex as sex, t_birth as birth from teacher
union
select s_name, s_sex, s_birth from student;
-- result
+--------+-----+---------------------+
| name | sex | birth |
+--------+-----+---------------------+
| 李誠 | 男 | 1958-12-02 00:00:00 |
| 王萍 | 女 | 1972-05-05 00:00:00 |
| 劉冰 | 女 | 1977-08-14 00:00:00 |
| 張旭 | 男 | 1969-03-12 00:00:00 |
| 曾華 | 男 | 1977-09-01 00:00:00 |
| 匡明 | 男 | 1975-10-02 00:00:00 |
| 王麗 | 女 | 1976-01-23 00:00:00 |
| 李軍 | 男 | 1976-02-20 00:00:00 |
| 王芳 | 女 | 1975-02-10 00:00:00 |
| 陸軍 | 男 | 1974-06-03 00:00:00 |
| 王尼瑪 | 男 | 1976-02-20 00:00:00 |
| 張全蛋 | 男 | 1975-02-10 00:00:00 |
| 趙鐵柱 | 男 | 1974-06-03 00:00:00 |
| 張飛 | 男 | 1974-06-03 00:00:00 |
+--------+-----+---------------------+
注意:連接兩個表時,兩個表的字段順序要保持一致。舉例來說,如果將上述student表的查詢順序換為s_sex,s_birth,s_name,則結果變為:
-- 字段順序不匹配結果
+------+---------------------+---------------------+
| name | sex | birth |
+------+---------------------+---------------------+
| 李誠 | 男 | 1958-12-02 00:00:00 |
| 王萍 | 女 | 1972-05-05 00:00:00 |
| 劉冰 | 女 | 1977-08-14 00:00:00 |
| 張旭 | 男 | 1969-03-12 00:00:00 |
| 男 | 1977-09-01 00:00:00 | 曾華 |
| 男 | 1975-10-02 00:00:00 | 匡明 |
| 女 | 1976-01-23 00:00:00 | 王麗 |
| 男 | 1976-02-20 00:00:00 | 李軍 |
| 女 | 1975-02-10 00:00:00 | 王芳 |
| 男 | 1974-06-03 00:00:00 | 陸軍 |
| 男 | 1976-02-20 00:00:00 | 王尼瑪 |
| 男 | 1975-02-10 00:00:00 | 張全蛋 |
| 男 | 1974-06-03 00:00:00 | 趙鐵柱 |
| 男 | 1974-06-03 00:00:00 | 張飛 |
+------+---------------------+---------------------+
除了字段順序要匹配,數量也要匹配,如果兩個union查詢的字段數量不一致,sql會進行報錯。
(3)查詢所有'女'教師和'女'學生的name,sex,birthday
select t_name as name, t_sex as sex, t_birth as birth from teacher where t_sex = '女'
union
select s_name, s_sex, s_birth from student where s_sex = '女';
總結:使用了別名之后的查詢字段仍然是原字段名
6.復制表數據做條件查詢
(1)查詢成績比該課程平均成績低的同學的成績表
select * from score as a
where grade < (select avg(grade) from score as b where a.c_no = b.c_no);
-- result
+------+-------+-------+
| s_no | c_no | grade |
+------+-------+-------+
| 105 | 3-245 | 75 |
| 105 | 6-166 | 79 |
| 109 | 3-105 | 76 |
| 109 | 3-245 | 68 |
| 109 | 6-166 | 81 |
+------+-------+-------+
總結:
查詢平均值的兩個方法:
a. 先按照某字段進行分組,再求每一組的平均值
select avg(grade) from score group by c_no ;
b.指定求某一條件的平均值
select avg(grade) from score where c_no = '3-105';
7.條件加分組篩選
(1) 查出至少有2名男生的班號
select s_class from student group by s_class having count(s_sex = '男') > 2;
也可以先查出男生的記錄,再按照班級分組,再寫計數的條件,如下:
select s_class from student where s_sex = '男' group by s_class having count(*) > 1;
-- result
+---------+
| s_class |
+---------+
| 95033 |
| 95031 |
+---------+
總結:
a. group by 對相同的字段值進行聚合,聚合后形成的各個分組可以使用sum,count,avg等聚合函數。如果要對分組加入條件,則使用having。詳情見:where和having的區別
b.count函數可以內置條件,但是最好加上or null 如:count(s_sex = '男' or null),具體原因見:count 中加條件為什么要加or null
8.模糊查詢
(1)year,now函數:查詢student 表中 不姓"王"的同學的記錄
select * from student where s_name not like '王%';
總結:
like和not like進行模糊匹配
9.高級函數
(1)查詢student 中每個學生的姓名和年齡
select s_name, year(now())- year(s_birth) as age from student;
-- result
+--------+------+
| s_name | age |
+--------+------+
| 曾華 | 44 |
| 匡明 | 46 |
| 王麗 | 45 |
| 李軍 | 45 |
| 王芳 | 46 |
| 陸軍 | 47 |
| 王尼瑪 | 45 |
| 張全蛋 | 46 |
| 趙鐵柱 | 47 |
| 張飛 | 47 |
+--------+------+
總結:
a.now()函數返回當前系統的日期;
b.year()函數返回日期類型的年份。
(2)多字段排序:以班級號和年齡從大到小的順序查詢student表中的全部記錄
select * from student order by s_class desc, s_birth;
-- result
+------+--------+-------+---------------------+---------+
| s_no | s_name | s_sex | s_birth | s_class |
+------+--------+-------+---------------------+---------+
| 110 | 張飛 | 男 | 1974-06-03 00:00:00 | 95038 |
| 103 | 王麗 | 女 | 1976-01-23 00:00:00 | 95033 |
| 104 | 李軍 | 男 | 1976-02-20 00:00:00 | 95033 |
| 107 | 王尼瑪 | 男 | 1976-02-20 00:00:00 | 95033 |
| 101 | 曾華 | 男 | 1977-09-01 00:00:00 | 95033 |
| 106 | 陸軍 | 男 | 1974-06-03 00:00:00 | 95031 |
| 109 | 趙鐵柱 | 男 | 1974-06-03 00:00:00 | 95031 |
| 105 | 王芳 | 女 | 1975-02-10 00:00:00 | 95031 |
| 108 | 張全蛋 | 男 | 1975-02-10 00:00:00 | 95031 |
| 102 | 匡明 | 男 | 1975-10-02 00:00:00 | 95031 |
+------+--------+-------+---------------------+---------+
--
總結:
第一排序規則放在前面,第二排序規則依次在后。