MySQL資料庫入門(七)多表查詢及大量練習
阿新 • • 發佈:2021-02-09
建表與資料準備
create database day4;
use day4;
# 建表
create table department(
id int unsigned not null unique,
name char(20)
);
create table employee(
id int unsigned primary key auto_increment,
name char(12) not null,
gender enum('male','female') not null default 'male',
age int unsigned,
dep_id int unsigned not null
);
# 寫入資料
insert into department values
(100,'技術'),
(101,'人事'),
(102,'銷售'),
(103,'運營');
# 免責宣告:以下名字均是faker name生成的,請勿對號入座。
insert into employee(name,gender,age,dep_id) values
('唐建華','male',18,100),
('黃淑珍','female' ,48,101),
('李暢','male',38,101),
('華桂珍','female',28,102),
('鍾濤','male',18,100),
('廖婷婷','female',18,104);
連表
不加條件的連表就是笛卡爾積,案例如下:
select *
from employee,department;
這樣生成了24條記錄,即左表6條×右表4條。這種連表方式極少用到,因為這樣生成太多冗餘資料。
內聯表相當於加了where條件的笛卡爾積:
select * from employee,department where employee. dep_id=department.id;
常用的連表方式是根據某個共同欄位將兩個表進行連表,一共有以下四種類型:
一、內連表
語法案例:
select *
from department
inner join employee
on department.id=employee.dep_id;
執行結果:
+-----+--------+----+-----------+--------+------+--------+
| id | name | id | name | gender | age | dep_id |
+-----+--------+----+-----------+--------+------+--------+
| 100 | 技術 | 1 | 唐建華 | male | 18 | 100 |
| 101 | 人事 | 2 | 黃淑珍 | female | 48 | 101 |
| 101 | 人事 | 3 | 李暢 | male | 38 | 101 |
| 102 | 銷售 | 4 | 華桂珍 | female | 28 | 102 |
| 100 | 技術 | 5 | 鍾濤 | male | 18 | 100 |
+-----+--------+----+-----------+--------+------+--------+
注意事項:
內連表會捨棄左表和右表兩邊不匹配的資料!
請認真看department表,這裡有4個部門;employee表,這裡有6個員工。
連表以後只有5條記錄,其中department表中“運營”記錄被捨棄,employee表中’廖婷婷’記錄被捨棄。
二、左外表
語法案例:
select *
from department
left join employee
on department.id=employee.dep_id;
執行結果:
+-----+--------+------+-----------+--------+------+--------+
| id | name | id | name | gender | age | dep_id |
+-----+--------+------+-----------+--------+------+--------+
| 100 | 技術 | 5 | 鍾濤 | male | 18 | 100 |
| 100 | 技術 | 1 | 唐建華 | male | 18 | 100 |
| 101 | 人事 | 3 | 李暢 | male | 38 | 101 |
| 101 | 人事 | 2 | 黃淑珍 | female | 48 | 101 |
| 102 | 銷售 | 4 | 華桂珍 | female | 28 | 102 |
| 103 | 運營 | NULL | NULL | NULL | NULL | NULL |
+-----+--------+------+-----------+--------+------+--------+
注意事項:
左外表會保留左表全部資料,捨棄右表不匹配的資料!
請認真看department表,這裡有4個部門;employee表,這裡有6個員工。
連表以後只有6條記錄,其中department表中的4條記錄齊全,employee表中’廖婷婷’記錄被捨棄。
三、右外連表
語法案例:
select *
from department
right join employee
on department.id=employee.dep_id;
執行結果:
+------+--------+----+-----------+--------+------+--------+
| id | name | id | name | gender | age | dep_id |
+------+--------+----+-----------+--------+------+--------+
| 100 | 技術 | 1 | 唐建華 | male | 18 | 100 |
| 101 | 人事 | 2 | 黃淑珍 | female | 48 | 101 |
| 101 | 人事 | 3 | 李暢 | male | 38 | 101 |
| 102 | 銷售 | 4 | 華桂珍 | female | 28 | 102 |
| 100 | 技術 | 5 | 鍾濤 | male | 18 | 100 |
| NULL | NULL | 6 | 廖婷婷 | female | 18 | 104 |
+------+--------+----+-----------+--------+------+--------+
注意事項:
右外表會保留右表全部資料,捨棄左表不匹配的資料!
請認真看department表,這裡有4個部門;employee表,這裡有6個員工。
連表以後只有6條記錄,其中department表中“運營”記錄被捨棄,employee表中6條記錄齊全。
四、全外連表
語法案例:
mysql不支援全外連表,但是可以使用union變通實現全外連表,程式碼如下:
select *
from department
left join employee
on department.id=employee.dep_id
union
select *
from department
right join employee
on department.id=employee.dep_id;
執行結果:
+------+--------+------+-----------+--------+------+--------+
| id | name | id | name | gender | age | dep_id |
+------+--------+------+-----------+--------+------+--------+
| 100 | 技術 | 5 | 鍾濤 | male | 18 | 100 |
| 100 | 技術 | 1 | 唐建華 | male | 18 | 100 |
| 101 | 人事 | 3 | 李暢 | male | 38 | 101 |
| 101 | 人事 | 2 | 黃淑珍 | female | 48 | 101 |
| 102 | 銷售 | 4 | 華桂珍 | female | 28 | 102 |
| 103 | 運營 | NULL | NULL | NULL | NULL | NULL |
| NULL | NULL | 6 | 廖婷婷 | female | 18 | 104 |
+------+--------+------+-----------+--------+------+--------+
注意事項:
全外連表不會捨棄任何資料!
請認真看department表,這裡有4個部門;employee表,這裡有6個員工。
連表練習
- 查詢所有人事部的員工名單:
select e.name 姓名
from department d # 部門表重新命名為d
inner join employee e #員工表重新命名為e
on d.id=e.dep_id # 部門表的id欄位與員工表的dep_id欄位建立內連線
where d.name='人事'; # 篩選部門名字是'人事'的記錄
- 查詢人事部年齡大於40歲的員工名單:
select e.name 姓名
from department d
inner join employee e
on d.id=e.dep_id
where d.name="人事" and e.age>40; # 篩選部門名字是人事且員工年齡大於40歲的記錄
- 查詢年齡大於20歲的員工及所在部門:
select e.name 姓名,d.name 部門
from department d
inner join employee e
on d.id=e.dep_id
where age>20;
- 查詢所有部門的名字和員工人數:
select d.name 部門,count(e.id) 人數
from department d
left join employee e
on d.id=e.dep_id
group by d.name; # 按部門名字進行分組
注意:這裡要用左外連表,因為所有的部門資料都要保留,不能遺漏沒人的部門。
5. 查詢所有部門的名字和員工人數,按人數從高到低排列:
select d.name 部門,count(e.id) 人數
from department d
left join employee e
on d.id=e.dep_id
group by d.name
order by 人數 desc; # 按人數從高到低排序
子查詢
子查詢是指查詢中巢狀查詢。
具體看下列案例:
- 查詢平均年齡在25歲以上的部門:
select d.name 部門
from department d
where id in( # 篩選部門id在平均年齡25歲以上的
select dep_id
from employee
group by dep_id # 按部門id分組
having avg(age)>25 # 按平均年齡過濾部門,只保留平均年齡大於25的
);
- 查詢不足1人的部門名(子查詢得到的是有人的部門id)
select name
from department d
where d.id not in(
select dep_id from employee
group by dep_id
having count(id)>=1
); # 這種寫法適用性更廣,若將1改成2可找出人數僅1人或不足1人的部門
- 查詢大於單位平均年齡的員工
select name,age
from employee
where age>( # 括號內子句中計算單位的平均年齡
select avg(age)
from employee
);
多表查詢總結:
- 遇到既可使用子查詢實現也可使用連表查詢實現的情況,優先考慮使用連表查詢,因為連表查詢效率比子查詢高。
- 寫多表查詢程式碼時要分層分步實現,每一步經過驗證無誤後,再將若干步驟拼接起來。
- 注重書寫格式,建議參考上述案例中select父句和子句縮排書寫格式,既可以方便書寫註釋又方便識別父句與子句,大大提高程式碼可讀性。
- 注意select語句的子句執行順序,請參照子句執行的順序書寫子句。