在DQL的基礎查詢中,我們已經學過了多表查詢的一種:聯合查詢(union)。本文我們將系統的講解多表查詢。
笛卡爾積現象
首先,我們想要查詢emp表和stu表兩個表,按照我們之前的知識棧,我們直接使用:
select * from emp,stu;
當查詢emp時:15條記錄被查詢
當查詢stu時:5條記錄被查詢
但是讓我們來觀察結果:
哇,查詢到了70條記錄?。而且根據結果我們可以看出:左表emp的每條記錄都會與右表stu的每條記錄組成一條新的記錄,也就是14*5=70條記錄。這種現象非常符合離散數學中學到的笛卡爾積的結果,所以我們將這種現象稱為笛卡爾積現象。
笛卡爾積(Cartesian Product):表示兩個集合之間的所有可能的有序對的集合
笛卡爾積的性質包括:
- 笛卡爾積的結果是一個新集合。
- 如果?AA?和?BB?其中一個為空集,則結果也為空集。
- 笛卡爾積的順序是重要的,即?A×B≠B×A。
我們如何實現15+4的結果呢?直接使用上面的select肯定是不行了。
那么,此時有一個叫聯合查詢的方式出現在腦海里:
聯合查詢
關鍵字:【union all】
select empno,ename,job from emp
union all
select id,nick,pwd from stu;
觀察結果:19=15+4條記錄 (使用union代替union all可以實現去重的功能)
但是為了將記錄查詢出來,我們 必須合適選擇每個表的字段,將兩個表查詢的字段的數據類型一一對應。empno int?= id int,ename varchar?= nick varchar ......
如果數據類型對應不上,那么將無法查詢,結果是:
直接查詢的條件限制法
那么聯合查詢也不能符合我們對查詢結果的預期,這時候需要我們轉換思路。從笛卡爾積現象開始:【需求:查詢員工表以及每個員工對應的部門信息】
首先直接查詢:
對于查詢的結果,雖然有重復, 但至少有我們需要的結果,那么只需要將這個表中的有效記錄提取出來,就可以了。也就是使用where條件進行限定:
此時我們查詢的結果就符合我們的預期了。但注意,這時候我們操作時必須給每個字段指定上是哪個表的字段,不然的話,該字段屬于二義性字段,無法通過語法分析,也就不能執行了。
內連接
select field from tb1
[inner] join tb2 on condition;
等值連接
eg.根據一個編號查另一個表中改編號對應的內容。常見于:根據子表外鍵連接父表主鍵
【練習:查詢員工表以及每個員工對應的部門信息】
select * from emp [inner]join dept on emp.DEPTNO = dept.DEPTNO;
非等值連接
eg.根據一個表的某個字段,查另一個表中該字段屬于哪段區間的信息。實際用途:等級劃分
【練習:根據員工的薪水查出薪水的等級】
自連接
eg.自連接是某個表的某個字段信息存儲的數據是本表的另一條記錄的信息。常用于:事物關聯
【練習:根據員工表的領導編號查詢領導的名字】
自連接的流程:為顯示的字段起別名(避免兩個結果字段名沖突,非必須)=》from選擇查詢表=》join 連接表(本表),并起別名(避免二義性,必須)=》連接條件。[過程中的每個字段都需要明確指出是哪個表]?
外連接
由于內連接會將連接條件的字段中空值的記錄給過濾掉,所以為了顯示較為全面的記錄,我們采用外連接的方式進行多表查詢。
左外連接
左外連接就是(left [outer] join ... on...)。顯示主表的所有字段,并將被連接的從表符合連接條件的記錄連接到主表,如果沒有,主表顯示原本記錄,從表的字段中為空。
【練習:查詢員工表以及每個員工對應的部門信息---顯示所有員工】
右外連接
右外連接就是(right?[outer] join ... on...)。與左外連接類似。
【練習:查詢員工表以及每個員工對應的部門信息---顯示所有部門】
我們對比發現,右外連接顯示的記錄比左外連接的記錄多一條,多出的一條是部門表中的數據,但該部門在員工表中沒有員工,所以全部顯示為空。
注:外連接查詢的結果記錄數 >= 內連接查詢到的結果記錄數
左外連接【左圖】、右外連接【右圖】
子查詢
子查詢:嵌套在其它SQL語句內的查詢語句,且必須出現在圓括號內(查詢一般是指select語句):子查詢的結果可以作為外層查詢的過濾條件或計算字段。
標量子查詢
子查詢返回結果是單個值,如數字、字符串、日期等最簡單的形式。這種子查詢稱為標量子查詢。【常用的操作符:| = | <> |?> | >= | < | <= |】
【練習:查詢銷售部的部門員工信息】
第一步:查詢銷售部的部門編號
select deptno from dept where dname="SALES";
第二步:查詢部門編號為上述結果的員工
select * from emp where deptno = 上條語句的結果;
第三步:合并一條語句:
select * from emp where deptno = (select deptno from dept where dname="SALES");
標量子查詢可以在子句中使用聚合函數、而且子句的位置還可以出現在select后作為字段出現:
【練習:查詢部門名,以及每個部門的人數】
select dname, (select count(*) from emp where dept.deptno=emp.deptno) emps
from dept;
列子查詢
子查詢的結果是一列(或者多列),這種子查詢稱為列子查詢。
【常用操作符:in、not in、any、some、all】
IN:在指定的集合范圍之內,多選一
NOT IN:不再指定的集合范圍之內
ANY:子查詢返回列表中,有任意一個滿足即可【相當于集合所有元素作 or 運算】
SOME:與ANY相同,SOME與ANY等價
ALL:子查詢返回列表的所有值都要滿足【相當于集合所有元素之間作 and 運算】
【練習:查詢銷售部(SALES)和調研部(RESEARCH)所有員工信息】
select *
from emp
where deptno in (select deptno from dept where dname in ("SALES","RESEARCH"));-- or:
select *
from emp
where deptno in (select deptno from dept where dname="SALES" or dname="RESEARCH");
【練習:查詢比銷售部的所有人的工資都高的員工信息】
比所有人都高,也就是sal > all( {...} )
通過這個練習,我們不僅練習了all運算,我們還知道了,子句可以嵌套子句。
行子查詢
子查詢的返回結果是一行(可以是多行),這種子查詢稱為行子查詢。
【常用操作符:| = | <> | in | not in】
【練習:查詢與“SMITH”的 薪資以及直屬領導 都相同的員工信息】
-- (單行結果)
select * from emp where (sal,mgr) = (select sal,mgr from emp where ename = "SMITH");-- (多行結果)
select * from emp where (sal,mgr) in (select sal,mgr from emp where ename = "SMITH");
通過該練習,我們掌握了新的知識:
(field1,field2,...,fieldn) 可以通過加圓括號的方式直接與行結果進行運算【= | <> | in | not in】?
表子查詢
子查詢的結果可以是多行多列,產生這種結果的子查詢稱為表子查詢。【常用操作符:IN】
這種就是行子查詢的 in 操作。
-- (多行結果)
select * from emp where (sal,mgr) in (select sal,mgr from emp where ename = "SMITH");
感謝大家!歡迎指導、詢問、探討知識!