多表查詢
測試數據
create table emp (id int,name char(10),sex char,dept_id int); insert emp values(1,"大黃","m",1); insert emp values(2,"老王","m",2); insert emp values(3,"老李","w",30); #一張表示部門表 #存在一些沒有員工的的部門 create table dept (id int,name char(10)); insert dept values(1,"市場"); insert dept values(2,"財務"); insert dept values(3,"行政");
1. 笛卡爾積查詢
# 笛卡爾積查詢, mysql> select *from dept,emp; +------+--------+------+--------+------+---------+ | id | name | id | name | sex | dept_id | +------+--------+------+--------+------+---------+ | 1 | 市場 | 1 | 大黃 | m | 1 | | 2 | 財務 | 1 | 大黃 | m | 1 | | 3 | 行政 | 1 | 大黃 | m | 1 | | 1 | 市場 | 2 | 老王 | m | 2 | | 2 | 財務 | 2 | 老王 | m | 2 | | 3 | 行政 | 2 | 老王 | m | 2 | | 1 | 市場 | 3 | 老李 | w | 30 | | 2 | 財務 | 3 | 老李 | w | 30 | | 3 | 行政 | 3 | 老李 | w | 30 | +------+--------+------+--------+------+---------+ 9 rows in set (0.00 sec) # 改進版 mysql> select *from dept,emp where dept.id = dept_id; +------+--------+------+--------+------+---------+ | id | name | id | name | sex | dept_id | +------+--------+------+--------+------+---------+ | 1 | 市場 | 1 | 大黃 | m | 1 | | 2 | 財務 | 2 | 老王 | m | 2 | +------+--------+------+--------+------+---------+
總結:
笛卡爾積查詢的結果,存在很多錯誤的數據。即數據關聯關系錯誤
解決辦法:
select *from dept,emp where dept.id = dept_id;
同時笛卡爾積的結果,會產生重復的字段信息
解決辦法:
select 指定字段... from dept,emp where dept.id = dept_id;
2. 內連接
內連接查詢本質上就是笛卡爾積查詢
mysql> select *from dept join emp ; +------+--------+------+--------+------+---------+ | id | name | id | name | sex | dept_id | +------+--------+------+--------+------+---------+ | 1 | 市場 | 1 | 大黃 | m | 1 | | 2 | 財務 | 1 | 大黃 | m | 1 | | 3 | 行政 | 1 | 大黃 | m | 1 | | 1 | 市場 | 2 | 老王 | m | 2 | | 2 | 財務 | 2 | 老王 | m | 2 | | 3 | 行政 | 2 | 老王 | m | 2 | | 1 | 市場 | 3 | 老李 | w | 30 | | 2 | 財務 | 3 | 老李 | w | 30 | | 3 | 行政 | 3 | 老李 | w | 30 | +------+--------+------+--------+------+---------+ 9 rows in set (0.00 sec) mysql> select *from dept join emp on dept.id=emp.dept_id; +------+--------+------+--------+------+---------+ | id | name | id | name | sex | dept_id | +------+--------+------+--------+------+---------+ | 1 | 市場 | 1 | 大黃 | m | 1 | | 2 | 財務 | 2 | 老王 | m | 2 | +------+--------+------+--------+------+---------+ 2 rows in set (0.00 sec)
3. 外連接:左連接
左邊的表無論是否能夠匹配 都要完整顯示,右邊即使沒有也要顯示出來
# 需求:要查詢所有員工以及所屬的部門信息 mysql> select * from emp left join dept on dept_id= dept.id; +------+--------+------+---------+------+--------+ | id | name | sex | dept_id | id | name | +------+--------+------+---------+------+--------+ | 1 | 大黃 | m | 1 | 1 | 市場 | | 2 | 老王 | m | 2 | 2 | 財務 | | 3 | 老李 | w | 30 | NULL | NULL | +------+--------+------+---------+------+--------+ 3 rows in set (0.00 sec) # 注意 在外連接查詢中 不能使用where關鍵字,必須使用on 專門來做表的對應關系
4. 外連接:右連接
右邊的表無論是否能夠匹配 都要完整顯示,左邊即使沒有也要顯示出來
select *from dept full join emp on dept.id = emp.dept_id;
5. 外連接:全連接(不支持)
無論是否匹配成功,兩邊表的數據都要全顯示
##mysql 不支持 select *from dept full join emp on dept.id = emp.dept_id; # 可以轉化一種思路,使用左連接 + 右連接 select *from dept left join emp on dept.id=emp.dept_id union select *from dept right join emp on dept.id=emp.dept_id;
6. union:聯合兩個表
過濾重復,即重復的數據不顯示。同時必須保證 兩個表的列數要相同
select * from emp union select * from emp; mysql> select * from emp -> union -> select * from emp; +------+--------+------+---------+ | id | name | sex | dept_id | +------+--------+------+---------+ | 1 | 大黃 | m | 1 | | 2 | 老王 | m | 2 | | 3 | 老李 | w | 30 | +------+--------+------+---------+ 3 rows in set (0.00 sec)
7. union all :
不過濾重復,即重復的數據可以顯示。同時必須保證 兩個表的列數要相同
select * from emp union all select * from emp; mysql> select * from emp -> union all -> select * from emp; +------+--------+------+---------+ | id | name | sex | dept_id | +------+--------+------+---------+ | 1 | 大黃 | m | 1 | | 2 | 老王 | m | 2 | | 3 | 老李 | w | 30 | | 1 | 大黃 | m | 1 | | 2 | 老王 | m | 2 | | 3 | 老李 | w | 30 | +------+--------+------+---------+ 6 rows in set (0.00 sec)
總結:
內連接表示,只顯示匹配成功的記錄。一般情況下,我們通常使用內連接
外連接表示,沒有匹配成功的也要顯示
練習:
測試數據
create table stu(id int primary key auto_increment,name char(10)); create table tea(id int primary key auto_increment,name char(10)); create table tsr(id int primary key auto_increment,t_id int,s_id int, foreign key(s_id) references stu(id), foreign key(t_id) references tea(id)); insert into stu values(null,"張三"),(null,"李四"); insert into tea values(null,"egon"),(null,"wer"); insert into tsr values(null,1,1),(null,1,2),(null,2,2);
需求:查出egon教過的學生
使用內連接:
mysql> select * from tea join tsr join stu on tea.id=tsr.t_id and tsr.s_id = stu.id where tea.name="egon"; +----+------+----+------+------+----+--------+ | id | name | id | t_id | s_id | id | name | +----+------+----+------+------+----+--------+ | 1 | egon | 1 | 1 | 1 | 1 | 張三 | | 1 | egon | 2 | 1 | 2 | 2 | 李四 | +----+------+----+------+------+----+--------+ 2 rows in set (0.00 sec) mysql> select stu.name from tea join tsr join stu on tea.id=tsr.t_id and tsr.s_id = stu.id where tea.name="egon"; +--------+ | name | +--------+ | 張三 | | 李四 | +--------+ 2 rows in set (0.00 sec)
使用子查詢:
# 先查出egon對應的id select id from tea where name="egon"; # 在tsr表中 查詢 egon 教過學生 的id select s_id from tsr where t_id = (select id from tea where name="egon"); # 在學生表中查詢出對應的id select stu.name from stu where id in (select s_id from tsr where t_id = (select id from tea where name="egon")); mysql> select * from tea where name="egon"; +----+------+ | id | name | +----+------+ | 1 | egon | +----+------+ 1 row in set (0.00 sec) mysql> select s_id from tsr where t_id = (select id from tea where name="egon"); +------+ | s_id | +------+ | 1 | | 2 | +------+ 2 rows in set (0.00 sec) mysql> select stu.name from stu where id in (select s_id from tsr where t_id = (select id from tea where name="egon")); +--------+ | name | +--------+ | 張三 | | 李四 | +--------+ 2 rows in set (0.27 sec)
通常情況下,內連接能夠查詢出來的數據,使用子查詢也能查詢出來