Python進階----多表查詢(內連,左連,右連), 子查詢(in,帶比較運算符)
一丶多表查詢
多表連接查詢的應用場景:
連接是關系數據庫模型的主要特點,也是區別於其他類型數據管理系的一個標志.
通常來說表與表之間的關系不必確定,也就時實體與實體之間的關系不緊密,檢索數據時,使用連表操作增強靈活性.可以再連表查詢時增加新的字段,為不同實體創建新的表.
多表聯查的基本語句:
# 多表連接查詢語法
select 字段
from 表1
INNER|LEFT|RIGHT join 表2
on 表1.字段=表2.字段;
# 條件過濾
where 條件
# 1.形成新的表
# 2.靈活的操控兩個表的所有字段
# 3.提高效率
交叉連接:
即笛卡爾積,將兩個表所有的記錄進行配對,數據大量冗余,沒有實際意義
### 查詢 employee 員工表 和 department 部門表的笛卡爾積
# 數據大量冗余 ,沒有實際意義
select * from employee,department;
+----+------------+--------+------+--------+------+--------------+
| id | name | sex | age | dep_id | id | name |
+----+------------+--------+------+--------+------+--------------+
| 1 | egon | male | 18 | 200 | 200 | 技術 |
| 1 | egon | male | 18 | 200 | 201 | 人力資源 |
| 1 | egon | male | 18 | 200 | 202 | 銷售 |
| 1 | egon | male | 18 | 200 | 203 | 運營 |
| 2 | alex | female | 48 | 201 | 200 | 技術 |
| 2 | alex | female | 48 | 201 | 201 | 人力資源 |
| 2 | alex | female | 48 | 201 | 202 | 銷售 |
| 2 | alex | female | 48 | 201 | 203 | 運營 |
| 3 | wupeiqi | male | 38 | 201 | 200 | 技術 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力資源 |
| 3 | wupeiqi | male | 38 | 201 | 202 | 銷售 |
| 3 | wupeiqi | male | 38 | 201 | 203 | 運營 |
| 4 | yuanhao | female | 28 | 202 | 200 | 技術 |
| 4 | yuanhao | female | 28 | 202 | 201 | 人力資源 |
| 4 | yuanhao | female | 28 | 202 | 202 | 銷售 |
| 4 | yuanhao | female | 28 | 202 | 203 | 運營 |
| 5 | liwenzhou | male | 18 | 200 | 200 | 技術 |
| 5 | liwenzhou | male | 18 | 200 | 201 | 人力資源 |
| 5 | liwenzhou | male | 18 | 200 | 202 | 銷售 |
| 5 | liwenzhou | male | 18 | 200 | 203 | 運營 |
| 6 | jingliyang | female | 18 | 204 | 200 | 技術 |
| 6 | jingliyang | female | 18 | 204 | 201 | 人力資源 |
| 6 | jingliyang | female | 18 | 204 | 202 | 銷售 |
| 6 | jingliyang | female | 18 | 204 | 203 | 運營 |
+----+------------+--------+------+--------+------+--------------+
內連接:
內連接是一種最常用的連接類型,兩個表的字段滿足的連接條件,只顯示兩張表中互相匹配的項,其他不匹配項的不顯示.
### 將員工表(employee)與部門表(department)進行連接, 員工表通過字段dep_id(部門id) 與 部門表字段id(部門id)進行連接
# 方式一 自連接 (特殊的內連接) 通過where 方式進行連接
select * from employee e ,department d where e.dep_id=d.id ;
# 結果
+----+-----------+--------+------+--------+------+--------------+
| id | name | sex | age | dep_id | id | name |
+----+-----------+--------+------+--------+------+--------------+
| 1 | egon | male | 18 | 200 | 200 | 技術 |
| 2 | alex | female | 48 | 201 | 201 | 人力資源 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力資源 |
| 4 | yuanhao | female | 28 | 202 | 202 | 銷售 |
| 5 | liwenzhou | male | 18 | 200 | 200 | 技術 |
+----+-----------+--------+------+--------+------+--------------+
# 方式二 通過內連接 ... inner join ... on方式連接
select * from employee e inner join department d on e.dep_id=d.id ;
# 結果
+----+-----------+--------+------+--------+------+--------------+
| id | name | sex | age | dep_id | id | name |
+----+-----------+--------+------+--------+------+--------------+
| 1 | egon | male | 18 | 200 | 200 | 技術 |
| 2 | alex | female | 48 | 201 | 201 | 人力資源 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力資源 |
| 4 | yuanhao | female | 28 | 202 | 202 | 銷售 |
| 5 | liwenzhou | male | 18 | 200 | 200 | 技術 |
+----+-----------+--------+------+--------+------+--------------+
外連接:
左外連接:
語法:A LEFT join B on A.XX=B.XX;
左表存顯示所有,右表沒有與左表匹配的則為 null.
右外連接:
語法:A RIGHT join B on A.XX=B.XX;
右表存顯示所有,左表沒有與右表匹配的則為 null.
### 員工表和部門表
# 左外連接 : 與左表沒有匹配的則顯示空,左表完全顯示
select * from employee e left join department d on e.dep_id=d.id;
# 結果:
+----+------------+--------+------+--------+------+--------------+
| id | name | sex | age | dep_id | id | name |
+----+------------+--------+------+--------+------+--------------+
| 1 | egon | male | 18 | 200 | 200 | 技術 |
| 5 | liwenzhou | male | 18 | 200 | 200 | 技術 |
| 2 | alex | female | 48 | 201 | 201 | 人力資源 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力資源 |
| 4 | yuanhao | female | 28 | 202 | 202 | 銷售 |
| 6 | jingliyang | female | 18 | 204 | NULL | NULL | #### 重點~~~
+----+------------+--------+------+--------+------+--------------+
# 右外連接 : 與右表沒有匹配的則顯示空,右表完全顯示
select * from employee e right join department d on e.dep_id=d.id;
# 結果:
+------+-----------+--------+------+--------+------+--------------+
| id | name | sex | age | dep_id | id | name |
+------+-----------+--------+------+--------+------+--------------+
| 1 | egon | male | 18 | 200 | 200 | 技術 |
| 2 | alex | female | 48 | 201 | 201 | 人力資源 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力資源 |
| 4 | yuanhao | female | 28 | 202 | 202 | 銷售 |
| 5 | liwenzhou | male | 18 | 200 | 200 | 技術 |
| NULL | NULL | NULL | NULL | NULL | 203 | 運營 | #### 重點~~
+------+-----------+--------+------+--------+------+--------------+
全連接:
union 關鍵字
mysql 不支持全外連接 full JOIN
mysql 使用 union 連接左連接和右連接,得到全連接
### union 全連接
# 必須是 左連接 + 右連接
select * from employee e left join department d on e.dep_id=d.id
union
select * from employee e right join department d on e.dep_id=d.id;
# 結果:
+------+------------+--------+------+--------+------+--------------+
| id | name | sex | age | dep_id | id | name |
+------+------------+--------+------+--------+------+--------------+
| 1 | egon | male | 18 | 200 | 200 | 技術 |
| 5 | liwenzhou | male | 18 | 200 | 200 | 技術 |
| 2 | alex | female | 48 | 201 | 201 | 人力資源 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力資源 |
| 4 | yuanhao | female | 28 | 202 | 202 | 銷售 |
| 6 | jingliyang | female | 18 | 204 | NULL | NULL | ### 重點 👈 ~~~
| NULL | NULL | NULL | NULL | NULL | 203 | 運營 | ### 重點 👈 ~~~
+------+------------+--------+------+--------+------+--------------+
### 全連接 錯誤用法
# 1. select * from employee e left join department d on e.dep_id=d.id 可以得到 左連接
# 2. select * from department d left join employee e on e.dep_id=d.id 通過調換表的順序可以得到和右連接一樣的效果
# 3. 但是 這樣組合起來的東西並不是全連接
select * from employee e left join department d on e.dep_id=d.id union select * from department d left join employee e on e.dep_id=d.id ;
# 結果:👇 這並不是全連接
+------+--------------+--------+-----------+--------+------+--------------+
| id | name | sex | age | dep_id | id | name |
+------+--------------+--------+-----------+--------+------+--------------+
| 1 | egon | male | 18 | 200 | 200 | 技術 |
| 5 | liwenzhou | male | 18 | 200 | 200 | 技術 |
| 2 | alex | female | 48 | 201 | 201 | 人力資源 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力資源 |
| 4 | yuanhao | female | 28 | 202 | 202 | 銷售 |
| 6 | jingliyang | female | 18 | 204 | NULL | NULL |
| 200 | 技術 | 1 | egon | male | 18 | 200 |
| 201 | 人力資源 | 2 | alex | female | 48 | 201 |
| 201 | 人力資源 | 3 | wupeiqi | male | 38 | 201 |
| 202 | 銷售 | 4 | yuanhao | female | 28 | 202 |
| 200 | 技術 | 5 | liwenzhou | male | 18 | 200 |
| 203 | 運營 | NULL | NULL | NULL | NULL | NULL |
+------+--------------+--------+-----------+--------+------+--------------+
准備employee 和 department 表:
#建表
create table department(
id int,
name varchar(20)
);
create table employee(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') not null default 'male',
age int,
dep_id int
);
#插入數據
insert into department values
(200,'技術'),
(201,'人力資源'),
(202,'銷售'),
(203,'運營');
insert into employee(name,sex,age,dep_id) values
('egon','male',18,200),
('alex','female',48,201),
('wupeiqi','male',38,201),
('yuanhao','female',28,202),
('liwenzhou','male',18,200),
('jingliyang','female',18,204)
;
練習題:
# 1. 以 內連接的方式 查詢employee和department表,並且employee表中的age字段值必須大於25,即找出年齡大於25歲的員工以及員工所在的部門
select e.name,d.name from employee e inner join department d on e.dep_id=d.id where e.age>25;
# 2. 以 內連接的方式 查詢employee和department表,年齡大於25 ,並且以age字段的升序方式顯示
select * from employee e inner join department d on e.dep_id=d.id where e.age>25 order by e.age;
# 3. 使用 自連接方式 查詢employee和department表,年齡大於25 ,並且以age字段的升序方式顯示
select * from employee e , department d where e.dep_id=d.id and e.age>25 order by e.age;
二丶子查詢
什么是子查詢:
1.子查詢是將一個查詢語句嵌套另一個語句中
2.內層查詢語句的結果,可以作為外層查詢的條件(where)
3.子查詢中可以包含:IN , NOT , ANY , ALL , EXISTS 和 NOT EXISTS等關鍵字
4.可以包含比較運算符: = , != , > , < 等
5.通俗:攜帶 兩個select 就是子查詢.
6.子查詢也可以作為字段(只能是單個值)
帶IN關鍵字的子查詢:
# 1. 查詢平均年齡在25歲以上的部門名
select * from department where id in (select dep_id from employee group by dep_id having avg(age));
# 2. 查看 '技術' 部員工姓名
select name from employee where dep_id=(select id from department where name='技術');
# 3.查看不足1人的部門名(子查詢得到的是有人的部門id)
select name from department where id not in(select dep_id from employee );
帶比較運算符的子查詢:
# 1. 查詢大於所有人平均年齡的員工名與年齡
select name,age from employee where age>(select avg(age) from employee);
# 2. 查詢大於部門內平均年齡的員工名、年齡
select e.name,e.age from employee e inner join (select dep_id,avg(age) as avg_age from employee group by dep_id) as t on e.dep_id =t.dep_id where e.age >avg_age ;
帶exists關鍵字的子查詢:
exists表示:內層查詢語句返回的是一個bool值,True時執行外層查詢,False時不執行外層查詢
# 1 . department表中存在dept_id=203,執行查詢員工表
select * from employee
where exists (select * from department where id=203);
# 結果:👇
mysql> select * from employee
-> where exists (select * from department where id=203);
+----+------------+--------+------+--------+
| id | name | sex | age | dep_id |
+----+------------+--------+------+--------+
| 1 | egon | male | 18 | 200 |
| 2 | alex | female | 48 | 201 |
| 3 | wupeiqi | male | 38 | 201 |
| 4 | yuanhao | female | 28 | 202 |
| 5 | liwenzhou | male | 18 | 200 |
| 6 | jingliyang | female | 18 | 204 |
+----+------------+--------+------+--------+
6 rows in set (0.00 sec)
# 2.department表中存在dept_id=205,執行查詢員工表
select * from employee
where exists (select * from department where id=205);
# 結果:👇
mysql> select * from employee
-> where exists (select * from department where id=205);
Empty set (0.00 sec)
select 字段 子查詢 (效率極低,不推薦使用,了解):
1.字段可以使一個子查詢,但是這個字段必須是唯一值,否則報錯
2.子查詢處理可以放在條件中,還可以放在連表中,還可以放在select字段(要求查詢的結果必須是一個單行單列的值)中.
## 准備 emp 表數據
create table emp(
id int not null unique auto_increment,
name varchar(20) not null,
sex enum('male','female') not null default 'male', #大部分是男的
age int(3) unsigned not null default 28,
hire_date date not null,
post varchar(50),
post_comment varchar(100),
salary double(15,2),
office int, #一個部門一個屋子
depart_id int
);
insert into emp(name,sex,age,hire_date,post,salary,office,depart_id) values
('egon','male',18,'20170301','老男孩駐沙河辦事處外交大使',7300.33,401,1), #以下是教學部
('alex','male',78,'20150302','teacher',1000000.31,401,1),
('wupeiqi','male',81,'20130305','teacher',8300,401,1),
('yuanhao','male',73,'20140701','teacher',3500,401,1),
('liwenzhou','male',28,'20121101','teacher',2100,401,1),
('jingliyang','female',18,'20110211','teacher',9000,401,1),
('jinxin','male',18,'19000301','teacher',30000,401,1),
('成龍','male',48,'20101111','teacher',10000,401,1),
('歪歪','female',48,'20150311','sale',3000.13,402,2),#以下是銷售部門
('丫丫','female',38,'20101101','sale',2000.35,402,2),
('丁丁','female',18,'20110312','sale',1000.37,402,2),
('星星','female',18,'20160513','sale',3000.29,402,2),
('格格','female',28,'20170127','sale',4000.33,402,2),
('張野','male',28,'20160311','operation',10000.13,403,3), #以下是運營部門
('程咬金','male',18,'19970312','operation',20000,403,3),
('程咬銀','female',18,'20130311','operation',19000,403,3),
('程咬銅','male',18,'20150411','operation',18000,403,3),
('程咬鐵','female',18,'20140512','operation',17000,403,3)
;
示例:select A表name ,B表age(通過關聯A表和B表的name字段) from A表
# 查詢 emp 表中的name 字段 和 employee 表中的age字段, 兩個表的的name字段進行關聯
select name as n ,(select age from employee as e where e.name=n ) as employee_Age from emp;
# 分析: n字段來自表emp , employee_Age字段來自 employee 字段
+------------+--------------+
| n | employee_Age |
+------------+--------------+
| egon | 18 |
| alex | 48 |
| wupeiqi | 38 |
| yuanhao | 28 |
| liwenzhou | 18 |
| jingliyang | 18 |
| jinxin | NULL |
| 成龍 | NULL |
| 歪歪 | NULL |
| 丫丫 | NULL |
| 丁丁 | NULL |
| 星星 | NULL |
| 格格 | NULL |
| 張野 | NULL |
| 程咬金 | NULL |
| 程咬銀 | NULL |
| 程咬銅 | NULL |
| 程咬鐵 | NULL |
+------------+--------------+
