進擊のpython
數據庫——多表查詢
其實最開始創建多表的目的就是為了將單表里的數據分出來
變成兩個三個表,為了邏輯清晰,也為了省內存,就多表分離了
但是,當我們想查看的時候,就需要將分離出來的東西“拼”回去
也就是我們接下來要講的,多表查詢~
那在開始之前,我們先准備兩個表:
#建表
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)
;
#查看表結構和數據
mysql> desc department;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
mysql> desc employee;
+--------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-----------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
| sex | enum('male','female') | NO | | male | |
| age | int(11) | YES | | NULL | |
| dep_id | int(11) | YES | | NULL | |
+--------+-----------------------+------+-----+---------+----------------+
mysql> select * from department;
+------+--------------+
| id | name |
+------+--------------+
| 200 | 技術 |
| 201 | 人力資源 |
| 202 | 銷售 |
| 203 | 運營 |
+------+--------------+
mysql> select * from employee;
+----+------------+--------+------+--------+
| 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 |
+----+------------+--------+------+--------+
哎哎哎別說我賦值賦錯了啊我是故意讓兩個表分別有一條對應不上的!
既然說是提到了多表查詢,畢竟也是查詢嘛,所以有的同學想這樣:
select * from department,employee;
mysql> select * from department,employee;
+------+--------------+----+------------+--------+------+--------+
| id | name | id | name | sex | age | dep_id |
+------+--------------+----+------------+--------+------+--------+
| 200 | 技術 | 1 | egon | male | 18 | 200 |
| 201 | 人力資源 | 1 | egon | male | 18 | 200 |
| 202 | 銷售 | 1 | egon | male | 18 | 200 |
| 203 | 運營 | 1 | egon | male | 18 | 200 |
| 200 | 技術 | 2 | alex | female | 48 | 201 |
| 201 | 人力資源 | 2 | alex | female | 48 | 201 |
| 202 | 銷售 | 2 | alex | female | 48 | 201 |
| 203 | 運營 | 2 | alex | female | 48 | 201 |
| 200 | 技術 | 3 | wupeiqi | male | 38 | 201 |
| 201 | 人力資源 | 3 | wupeiqi | male | 38 | 201 |
| 202 | 銷售 | 3 | wupeiqi | male | 38 | 201 |
| 203 | 運營 | 3 | wupeiqi | male | 38 | 201 |
| 200 | 技術 | 4 | yuanhao | female | 28 | 202 |
| 201 | 人力資源 | 4 | yuanhao | female | 28 | 202 |
| 202 | 銷售 | 4 | yuanhao | female | 28 | 202 |
| 203 | 運營 | 4 | yuanhao | female | 28 | 202 |
| 200 | 技術 | 5 | liwenzhou | male | 18 | 200 |
| 201 | 人力資源 | 5 | liwenzhou | male | 18 | 200 |
| 202 | 銷售 | 5 | liwenzhou | male | 18 | 200 |
| 203 | 運營 | 5 | liwenzhou | male | 18 | 200 |
| 200 | 技術 | 6 | jingliyang | female | 18 | 204 |
| 201 | 人力資源 | 6 | jingliyang | female | 18 | 204 |
| 202 | 銷售 | 6 | jingliyang | female | 18 | 204 |
| 203 | 運營 | 6 | jingliyang | female | 18 | 204 |
+------+--------------+----+------------+--------+------+--------+
誒??分析一下!這是把department的每一條數據都和employee的每一條數據組合起來打印了
雖然說打印出來的東西沒啥用,但是確實兩個表連在一起了~
而這種情況叫做:笛卡爾積
再繼續分析,其實也並不是都沒用,employee(dep_id)和department(id)相等的數據才是對我們有用的
那如何拿到這種數據呢?
select * from department,employee having department.id = employee.dep_id;
mysql> select * from department,employee having department.id = employee.dep_id;
+------+--------------+----+-----------+--------+------+--------+
| id | name | id | name | sex | age | dep_id |
+------+--------------+----+-----------+--------+------+--------+
| 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 |
+------+--------------+----+-----------+--------+------+--------+
5 rows in set (0.32 sec)
這是不是就是我們想要的東西了~
但是!!!!發現了嗎?沒有對應的數據,沒取出來(dep_id = 204的數據和id=203的數據)
還要說明的是,這么寫可不可以?可以,但是不推薦這么寫
mysql提供了方法來解決這個問題,其實這些方法的本質都是在笛卡爾積的基礎上進行的操作
看來我們錯怪笛卡爾積了,他還是挺有用的
一共有四種方法:內連接,左連接,右連接,全(外)連接
內連接
內連接就是查找兩個表的公共部分
select * from employee inner join department on department.id = employee.dep_id;
關聯表 inner join 被關聯表 on 條件
mysql> select * from employee inner join department on department.id = employee.dep_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 | 技術 |
+----+-----------+--------+------+--------+------+--------------+
5 rows in set (0.00 sec)
左連接
左連接就是在保證公共部分的基礎上,保留左表
select * from employee left join department on department.id = employee.dep_id;
mysql> select * from employee left join department on department.id = employee.dep_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 |
+----+------------+--------+------+--------+------+--------------+
6 rows in set (0.00 sec)
是不是坐標中沒有關聯的也打印出來了
右連接
左連接都會了,右連接不會?說不過去吧!
定義自己定義
select * from employee right join department on department.id = employee.dep_id;
mysql> select * from employee right join department on department.id = employee.dep_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 | 運營 |
+------+-----------+--------+------+--------+------+--------------+
6 rows in set (0.00 sec)
全(外)連接
你猜猜這是是干什么的?
(保證公共部分的基礎上,保留左右表)
有的想這么做:
select * from employee full join department on department.id = employee.dep_id;
結果報錯了,因為MySQL是不支持full join的 別的數據庫是支持的
所以我們可以拿到左右連接再去重,是不是就是全(外)連接了?可太機智了!
union 聯合去重
select * from employee left join department on department.id = employee.dep_id
union
select * from employee right join department on department.id = employee.dep_id;
mysql> select * from employee left join department on department.id = employee.dep_id
-> union
-> select * from employee right join department on department.id = employee.dep_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 | 運營 |
+------+------------+--------+------+--------+------+--------------+
7 rows in set (0.00 sec)
是不是就完美解決了~