SQL進階-多表查詢及相關習題講解

前言

緊接着之前敘述過的SQL常用語句總結,在這一篇博客中南國也有對多表查詢進行了一些敘述,但經過這段時間的筆試面試經歷,感覺自己對這塊知識的理解 還不夠深入。
所以,在這篇SQL進階中,南國對SQL經常用到的多表知識點在做一個詳細的講解。

提到關係數據庫中的多表查詢時,你會想到什麼呢??
你是不是想說多表查詢就是同時查詢幾張不同的表 通過表與表之間的數據的主外鍵聯繫 查詢得到想要的數據結果。 當然這個回答已經很不錯了,準確的說 多表查詢還可以包括同一個數據表中查詢大於某行特定數據的查詢。

多表查詢有如下幾種:

  • 合併結果集;
  • 連接查詢
    內連接
    外連接:左外連接,右外連接,全外連接(MySQL不支持)
    自然連接
  • 子查詢

下面我們對這些方法展開敘述:

1. 合併結果集

這個在前面的博客中,這裏我簡要敘述一下:
1.作用:合併結果集就是把兩個select語句的查詢結果合併到一起!
2.合併結果集有兩種方式:

  • UNION:去除重複記錄,例如:SELECT * FROM t1 UNION SELECT * FROM t2;
  • UNION ALL:不去除重複記錄,例如:SELECT * FROM t1 UNION ALL SELECT * FROM t2。
    在這裏插入圖片描述
    在這裏插入圖片描述
    3.要求:被合併的兩個結果:列數、列類型必須相同。

2. 連接查詢

連接查詢就是求出多個表的乘積,例如t1連接t2,那麼查詢出的結果就是t1*t2。
在這裏插入圖片描述
連接查詢會產生笛卡爾積,假設集合A={a,b},集合B={0,1,2},則兩個集合的笛卡爾積爲{(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}。可以擴展到多個集合的情況。
那麼多表查詢產生這樣的結果並不是我們想要的,那麼怎麼去除重複的,不想要的記錄呢,當然是通過條件過濾。通常要查詢的多個表之間都存在關聯關係,那麼就通過關聯關係去除笛卡爾積。

假如現在有兩張表,emp表一共14行記錄,dept表一共4行記錄,那麼連接後查詢出的結果是56行記錄。
也就你只是想在查詢emp表的同時,把每個員工的所在部門信息顯示出來,那麼就需要使用主外鍵來去除無用信息了。

SELECT * FROM emp,dept WHERE emp.deptno=dept.deptno;

在這裏插入圖片描述
上面查詢結果會把兩張表的所有列都查詢出來,也許你不需要那麼多列,這時就可以指定要查詢的列了。

SELECT emp.ename,emp.sal,emp.comm,dept.dname 
FROM emp,dept 
WHERE emp.deptno=dept.deptno;

在這裏插入圖片描述

2.1 內連接

上面的連接語句就是內連接,但它不是SQL標準中的查詢方式,可以理解爲方言!SQL標準的內連接爲:

SELECT * 
FROM emp e 
INNER JOIN dept d 
ON e.deptno=d.deptno;

INNER可以省略,因爲MySQL默認的連接方式就是內連接

內連接的特點:查詢結果必須滿足條件。例如我們向emp表中插入一條記錄:
在這裏插入圖片描述
其中deptno爲50,而在dept表中只有10、20、30、40部門,那麼上面的查詢結果中就不會出現“張三”這條記錄,因爲它不能滿足e.deptno=d.deptno這個條件。

2.2 外連接(左連接、右連接)

外連接的特點:查詢出的結果存在不滿足條件的可能

左連接:

SELECT * FROM emp e 
LEFT OUTER JOIN dept d 
ON e.deptno=d.deptno;

這裏OUTER關鍵字可以省略
左連接是先查詢出左表(即以左表爲主),然後查詢右表,右表中滿足條件的顯示出來,不滿足條件的顯示NULL。

例如:其中emp表中“張三”這條記錄中,部門編號爲50,而dept表中不存在部門編號爲50的記錄,所以“張三”這條記錄,不能滿足e.deptno=d.deptno這條件。但在左連接中,因爲emp表是左表,所以左表中的記錄都會查詢出來,即“張三”這條記錄也會查出,但相應的右表部分顯示NULL。
在這裏插入圖片描述
右連接:

SELECT * FROM emp e 
RIGHT OUTER JOIN dept d 
ON e.deptno=d.deptno;

右連接就是先把右表中所有記錄都查詢出來,然後左表滿足條件的顯示,不滿足顯示NULL。例如在dept表中的40部門並不存在員工,但在右連接中,如果dept表爲右表,那麼還是會查出40部門,但相應的員工信息爲NULL。
在這裏插入圖片描述
連接不限與兩張表,連接查詢也可以是三張、四張,甚至N張表的連接查詢。通常連接查詢不可能需要整個笛卡爾積,而只是需要其中一部分,那麼這時就需要使用條件來去除不需要的記錄。這個條件大多數情況下都是使用主外鍵關係去除。
兩張表的連接查詢一定有一個主外鍵關係,三張表的連接查詢就一定有兩個主外鍵關係,所以在大家不是很熟悉連接查詢時,首先要學會去除無用笛卡爾積,那麼就是用主外鍵關係作爲條件來處理。如果兩張表的查詢,那麼至少有一個主外鍵條件,三張表連接至少有兩個主外鍵條件。

2.3 自然查詢

自然連接是把同名列通過等值連接起來的,同名列可以有多個。在等值連接中那目標列中重複的屬性列去掉則爲自然連接。

內連接和自然連接的區別:內連接提供連接的列,而自然連接自動連接所有同名列。

select Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
from Student,SC where Student.Sno=SC.Sno;

3. 子查詢

子查詢就是嵌套查詢,即SELECT中包含SELECT,如果一條語句中存在兩個,或兩個以上SELECT,那麼就是子查詢語句了。

  • 子查詢出現的位置:
    where後,作爲條件的一部分;
    from後,作爲被查詢的一條表;
  • 當子查詢出現在where後作爲條件時,還可以使用如下關鍵字:
    any
    all
  • 子查詢結果集的形式:
    單行單列(用於條件)
    單行多列(用於條件)
    多行單列(用於條件)
    多行多列(用於表)

關於子查詢的理論講解,我在博客SQL常用語句總結有更新過。子查詢比較重要,也應用的比較多。
這裏我主要是結合之前的博客 對一些題型做剖析。

1.工資高於甘寧的員工。

分析:
查詢條件:工資>甘寧工資,其中甘寧工資需要一條子查詢。

第一步:查詢甘寧的工資
SELECT sal FROM emp WHERE ename=‘甘寧’

第二步:查詢高於甘寧工資的員工
SELECT * FROM emp WHERE sal > (${第一步})

結果:
SELECT * FROM emp WHERE sal > (SELECT sal FROM emp WHERE ename=‘甘寧’)

  • 子查詢作爲條件
  • 子查詢形式爲單行單列

2.工資高於30部門所有人的員工信息

分析:
查詢條件:工資高於30部門所有人工資,其中30部門所有人工資是子查詢。高於所有需要使用all關鍵字。

第一步:查詢30部門所有人工資
SELECT sal FROM emp WHERE deptno=30;

第二步:查詢高於30部門所有人工資的員工信息
SELECT * FROM emp WHERE sal > ALL (${第一步})

結果:
SELECT * FROM emp WHERE sal > ALL (SELECT sal FROM emp WHERE deptno=30)

  • 子查詢作爲條件
  • 子查詢形式爲多行單列(當子查詢結果集形式爲多行單列時可以使用ALL或ANY關鍵字)

3.查詢工作和工資與殷天正完全相同的員工信息

分析:
查詢條件:工作和工資與殷天正完全相同,這是子查詢

第一步:查詢出殷天正的工作和工資
SELECT job,sal FROM emp WHERE ename=‘殷天正’

第二步:查詢出與殷天正工作和工資相同的人
SELECT * FROM emp WHERE (job,sal) IN (${第一步})

結果:
SELECT * FROM emp WHERE (job,sal) IN (SELECT job,sal FROM emp WHERE ename=‘殷天正’)

  • 子查詢作爲條件
  • 子查詢形式爲單行多列

4.查詢員工編號爲1006的員工名稱、員工工資、部門名稱、部門地址

分析:
查詢列:員工名稱、員工工資、部門名稱、部門地址
查詢表:emp和dept,分析得出,不需要外連接(外連接的特性:某一行(或某些行)記錄上會出現一半有值,一半爲NULL值)
條件:員工編號爲1006

第一步:去除多表,只查一張表,這裏去除部門表,只查員工表
SELECT ename, sal FROM emp e WHERE empno=1006

第二步:讓第一步與dept做內連接查詢,添加主外鍵條件去除無用笛卡爾積
SELECT e.ename, e.sal, d.dname, d.loc
FROM emp e, dept d
WHERE e.deptno=d.deptno AND empno=1006

第二步中的dept表表示所有行所有列的一張完整的表,這裏可以把dept替換成所有行,但只有dname和loc列的表,這需要子查詢。

第三步:查詢dept表中dname和loc兩列,因爲deptno會被作爲條件,用來去除無用笛卡爾積,所以需要查詢它。
SELECT dname,loc,deptno FROM dept;

第四步:替換第二步中的dept
SELECT e.ename, e.sal, d.dname, d.loc
FROM emp e, (SELECT dname,loc,deptno FROM dept) d
WHERE e.deptno=d.deptno AND e.empno=1006

  • 子查詢作爲表
  • 子查詢形式爲多行多列

(2019.04.08更新)
這裏再分享一個經典的SQL語句初級練習的博客經典數據庫SQL語句編寫練習題, 供大家學習鞏固知識點

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章