SQL Server 數據庫基本操作入門篇【5】

本文主講數據查詢中的 連接查詢嵌套查詢(部分),歡迎閱讀~


一、連接查詢

連接查詢: 同時涉及兩個及以上的表的查詢

  • 連接條件: 用來連接兩個表的條件
    [<表名1>.]<列名1> <比較運算符> [<表名2>.]<列名2>
    比如:Student.Sno = SC.Sno
  • 連接字段: 連接條件中的列名稱
    如:Sno就是上面例子中的連接字段
    (ps:連接字段類型必須是可比的,但名字不必相同

1. 等值與非等值連接查詢

當連接運算符爲=時,稱爲等值連接;使用其他運算符稱爲非等值連接

等值連接: 連接運算符爲 =
🌟來看例子: 查詢每個學生及其選修課程的情況:

SELECT Student.*, SC.*
FROM   Student, SC
WHERE  Student.Sno = SC.Sno;
  • 關係代數中的等值連接:StudentStudent.Sno=SC.Sno\underset{Student.Sno = SC.Sno}\JoinSC

(這裏爲了省事兒,SELECT Student.*, SC.*可簡寫爲SELECT *
如圖等值連接即直接把兩個表拼在一起了,會有重複的列,如圖中的Sno,一會兒要寫的自然連接就是去掉了重複列。
在這裏插入圖片描述

  • 這裏如果不寫條件即沒有WHERE條件表達式,則打印出的是兩個表的笛卡爾積(如下圖,列數即兩表的列數之和,行數即兩表的行數之積,所以有10*9=90個元組,5+3=8個屬性列)
    在這裏插入圖片描述

自然連接
🌟來看例子: 用自然連接完成上面的那個例子:(即去掉重複列Sno)

SELECT Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade
FROM   Student, SC
WHERE  Student.Sno = SC.Sno;

在這裏插入圖片描述
一條SQL語句可以同時完成選擇和連接查詢
🌟來看例子: 查詢選修2號課程且成績在80分以上的所有學生的學號和姓名:

SELECT Student.Sno, Sname
FROM   Student, SC
WHERE  Student.Sno = SC.Sno AND    		               
       SC.Cno = '2' AND SC.Grade > 80;
       
SELECT *
FROM   Student, SC
WHERE  Student.Sno = SC.Sno;  /*把總的打印出來對照*/  

在這裏插入圖片描述
· 執行過程:
先從SC中選擇出Cno='2’且Grade>90的元組形成一個中間關係,再和Student滿足連接條件的元組進行連接得到最終的結果(這裏講解操作爲主,具體的執行過程、方法等我將會在【吐血整理】系列裏詳細介紹)
(ps:連接操作的執行方法有嵌套循環法、排序合併法等等,不同的DBMS執行方法可能會有所區別,不過出發點都是因爲連接查詢比較費時間,通過採用先進的高效的方法來優化,提高效率)

2. 自身連接

自身連接: 一個表與其自己進行連接
· 需要給表起別名以示區別(這裏只是給它起別名來當作兩個或多個表,當實際上它仍然只是一個表,我們仍然只是在對同一個表進行操作)
· 所有屬性名都是同名屬性,因此必須使用“別名”
🌟來看例子: 查詢每一門課的間接先修課(即先修課的先修課):

SELECT FIRST.Cno, SECOND.Cpno
FROM   Course FIRST, Course SECOND
WHERE  FIRST.Cpno = SECOND.Cno;

該題求間接先修課,拿下圖中的 1 數據庫 課程舉例:它的先修課Cpno是 5 數據結構,所以數據結構的課程號Cno是等於數據庫的Cpno的,而數據結構的先修課Cpno是 7 Pascal語言,所以 1 數據庫 的間接先修課就是 7 Pascal語言
在這裏插入圖片描述

3. 外連接

外連接與普通連接的區別:

  • ⋈ 普通連接操作只輸出滿足連接條件的元組
  • 外連接操作以指定表爲連接主體,將主體表中不滿足連接條件的元組一併輸出

外連接分三類:左外連接(LEFT OUTER JOIN)、右外連接(RIGHT OUTER JOIN)、全外連接(FULL OUTER JOIN
(ps:OUTER可省略)
⟕ 左外連接: 列出左邊關係中所有的元組 (即還返回左表中不符合連接條件只符合查詢條件的數據行)
⟖ 右外連接: 列出右邊關係中所有的元組 (即還返回右表中不符合連接條件只符合查詢條件的數據行)
⟗ 全外連接:不僅返回左表中不符合連接條件只符合查詢條件的數據行,並且還返回右表中不符合連接條件只符合查詢條件的數據行(全外連接實際是上左外連接和右外連接的數學合集(去掉重複),即全外連接 = 左外連接 UNION 右外連接

🌟來看例子: 改寫上面等值連接的例子:查詢每個學生及其選修課程的情況:
1)左外連接

SELECT Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade
FROM   Student LEFT OUTER JOIN SC ON  (Student.Sno = SC.Sno);  /*LEFT OUTER JOIN可簡寫爲LEFT JOIN*/

SELECT *
FROM   Student, SC
WHERE  Student.Sno = SC.Sno;   /*對照等值連接*/

在這裏插入圖片描述
對比等值連接,這裏的左外連接把Student學生表中Cno課程號爲空和Sdept爲空(不符合連接條件只符合查詢條件的數據行)的也都打印了出來,即沒選課的學生也在其查詢範圍內。
(ps:左外連接的查詢結果更適用於班主任(瞭解全班學生的選課情況),而科任老師更喜歡等值連接的結果,因爲課程空的學生就是沒選他課的學生,不屬於自己操心的範圍)

2)右外連接

SELECT Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade
FROM   Student RIGHT OUTER JOIN SC ON  (Student.Sno = SC.Sno);  /*RIGHT OUTER JOIN可簡寫爲RIGHT JOIN*/

SELECT *
FROM   Student, SC
WHERE  Student.Sno = SC.Sno;   /*對照等值連接*/

在這裏插入圖片描述
可見SC表中沒有不符合連接條件只符合查詢條件的數據行,即SC表的所有元組都符合連接條件
3)全外連接

SELECT Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade
FROM   Student FULL OUTER JOIN SC ON  (Student.Sno = SC.Sno);  /*FULL OUTER JOIN可簡寫爲FULL JOIN*/

SELECT *
FROM   Student, SC
WHERE  Student.Sno = SC.Sno;   /*對照等值連接*/

在這裏插入圖片描述
因爲右表(即SC表)沒有不符合連接條件只符合查詢條件的數據行,所以這裏的全外連接結果等於左外連接。

4. 多表連接

多表連接即 兩個以上的表進行連接

🌟直接來看例子: 查詢每個學生的學號、姓名、選修的課程名及成績:

SELECT Student.Sno, Sname, Cname, Grade
FROM   Student, SC, Course    /*多表連接*/
WHERE  Student.Sno = SC.Sno 
        AND SC.Cno = Course.Cno;

SELECT *
FROM   Student, SC, Course  
WHERE  Student.Sno = SC.Sno 
        AND SC.Cno = Course.Cno;   /*老規矩,打印粗來對照*/

該題姓名只有Student表有,選修的課程名只有Course表有,成績只有SC表有,所以需要用到三張表
在這裏插入圖片描述


二、嵌套查詢

嵌套查詢:
· 一個SELECT-FROM-WHERE語句稱爲一個查詢塊
·一個查詢塊嵌套在另一個查詢塊WHERE子句或HAVING短語的條件中的查詢稱爲嵌套查詢
例如 如下形式:

SELECT Sname	/*外層查詢/父查詢*/
FROM   Student
WHERE  Sno IN
          ( SELECT Sno        /*內層查詢/子查詢*/
            FROM   SC
            WHERE  Cno= '2');

SQL語言允許多層嵌套查詢: 即一個子查詢中還可以嵌套其他子查詢
子查詢的限制: 不能使用ORDER BY子句

  • 不相關子查詢: 子查詢的查詢條件不依賴於父查詢
    由裏向外 逐層處理: 即每個子查詢在上一級查詢處理之前求解,子查詢的結果用於建立其父查詢的查找條件
    例如:
SELECT Sno, Sname, Sdept
FROM   Student
WHERE  Sdept IN
            ( SELECT Sdept
              FROM   Student
              WHERE  Sname = '劉晨');
  • 相關子查詢: 子查詢的查詢條件依賴於父查詢
    首先取外層查詢中表的第一個元組,根據它與內層查詢相關的屬性值處理內層查詢,若WHERE子句返回值爲真,則取此元組放入結果表
    然後再取外層表的下一個元組
    重複這一過程,直至外層表全部檢查完爲止
    (如下代碼塊所示:從外層查詢中取出SC的一個元組x,將元組x的Sno值傳送給內層查詢,執行內層查詢,得到值AVG(Grade),用該值代替內層查詢,得到外層查詢)
SELECT Sno, Cno
FROM   SC x
WHERE  Grade >= ( SELECT AVG (Grade) 
                  FROM   SC y
                  WHERE  y.Sno = x.Sno);

1. 帶有IN謂詞的子查詢

🌟直接來看例子: 查詢與“劉晨 ”在同一個系學習的學生:
(這裏的題意爲:知道劉晨,但不知道她在哪個系,所以找與她在同一個系的學生需要先知道她是那一個系的)
方法一:分步完成
① 確定“劉晨”所在系名

SELECT Sdept  
FROM   Student                            
WHERE  Sname = '劉晨';

查詢結果爲:CS,用作第二步的查詢條件
② 查找所有在CS系學習的學生。

SELECT Sno, Sname, Sdept     
FROM   Student                 
WHERE  Sdept = 'CS';

方法二:將第一步查詢嵌入到第二步查詢的條件中

SELECT Sno, Sname, Sdept
FROM   Student
WHERE  Sdept IN
            ( SELECT Sdept
              FROM   Student
              WHERE  Sname = '劉晨');

在這裏插入圖片描述
此查詢爲 不相關子查詢
方法三:用自身連接(關鍵在於起別名!)

SELECT S1.Sno, S1.Sname, S1.Sdept
FROM   Student S1, Student S2
WHERE  S1.Sdept = S2.Sdept AND S2.Sname = '劉晨';

在這裏插入圖片描述
這個連接查詢的意思可理解爲: 列出Sdept系別相同的所有學生,且劉晨是這個系別的
(ps:對於這個題來說,嵌套查詢比連接查詢在邏輯上要更清晰一些)

🌟Another one: 查詢選修了課程名爲“信息系統”的學生學號和姓名:
利用帶有IN謂詞的子查詢:

SELECT Sno, Sname        /* 3.最後在Student關係中取出Sno和Sname */
FROM   Student                          
WHERE  Sno IN
          ( SELECT Sno        /* 2.然後在SC關係中找出選修了3號課程的學生學號 */
            FROM   SC                         
            WHERE  Cno IN
                      ( SELECT Cno      /* 1.首先在Course關係中找出“信息系統”的課程號,爲3號 */
                        FROM  Course           
                        WHERE Cname = '信息系統'                      
                      )
           );

用連接查詢實現:

SELECT Student.Sno, Sname    /*注意!!採用連接查詢時這裏Sno一定要寫清楚表頭是哪個表!!!*/
FROM   Student, SC, Course
WHERE  Student.Sno = SC.Sno AND
               SC.Cno = Course.Cno AND
               Course.Cname = '信息系統';

在這裏插入圖片描述
· 3層及以上的查詢採用連接查詢會更簡潔一些,但是理解起來帶IN謂詞的嵌套查詢要容易理解一些,看情況而用吧。

2. 帶有比較運算符的子查詢

當能確切知道內層查詢返回單值時,可用比較運算符(>,<,=,>=,<=,!= 或 <>均表示不等於)

🌟來看例子: 同上面的 查詢與“劉晨”在同一個系的學生:
(由於一個學生只可能在一個系學習,則可以用 = 代替IN )

SELECT Sno, Sname, Sdept
FROM   Student
WHERE  Sdept  =
             ( SELECT Sdept
               FROM   Student
               WHERE  Sname = '劉晨');

在這裏插入圖片描述
🌟Another one: 找出每個學生超過他選修課程平均成績的課程號:
(即上面講相關子查詢時候的例子)

SELECT Sno, Cno
FROM   SC x
WHERE  Grade >= ( SELECT AVG (Grade) 
                  FROM   SC y
                  WHERE  y.Sno = x.Sno);
                  SELECT * FROM   SC;
                  
SELECT * FROM  SC;   /*打印出整張表對照*/

SELECT AVG(Grade)
FROM   SC
WHERE  Sno = '201215121';   /*這裏我就只打印其中一個學生的平均分叭,要想看其他的換學號就可*/

(執行過程:從外層查詢中取出SC的一個元組x,將元組x的Sno值傳送給內層查詢,執行內層查詢,得到值AVG(Grade),用該值代替內層查詢,得到外層查詢)
在這裏插入圖片描述

3. 帶有ANY(SOME)或ALL謂詞的子查詢

使用ANY或ALL謂詞時必須同時使用比較運算
語義爲:

  • > ANY:大於子查詢結果中的某個值(> ANY 表示至少大於一個值,即大於最小值
    > ALL:大於子查詢結果中的所有值(> ALL 表示大於每一個值,即大於最大值
  • < ANY:小於子查詢結果中的某個值(< ANY 表示至少小於一個值,即小於最大值
    < ALL:小於子查詢結果中的所有值(< ALL 表示小於每一個值,即小於最小值
  • >= ANY:大於等於子查詢結果中的某個值(大於等於最小值)
    >= ALL:大於等於子查詢結果中的所有值(大於等於最大值)

如果還是不太清楚的話,趕緊來看看例子叭~
🌟來看例子: 查詢 計算機科學系中比計算機科學系 任意一個 學生年齡的學生姓名和年齡:

SELECT Sname, Sage
FROM   Student
WHERE  Sage < ANY (SELECT Sage
                   FROM   Student
                   WHERE  Sdept = 'CS')
       AND Sdept <> 'CS';       /*這是父查詢塊中的另一個條件:非CS系*/
       
SELECT Sname, Sage
FROM   Student
WHERE  Sage < 
		   ( SELECT MAX (Sage)
		     FROM   Student
		     WHERE  Sdept = 'CS ')   /*這裏題中要求爲比任意一個學生小,所以就是小於其最大值*/
       AND Sdept <> 'CS';
 
SELECT * FROM Student

在這裏插入圖片描述
採用ANY謂詞嵌套查詢的執行過程:
1)首先處理子查詢,找出CS系中所有學生的年齡,構成一個集合(20,19)
2)處理父查詢,找所有不是CS系年齡小於20或19(即小於最大值20)的學生
(ps:如果ANY對於你還是不太好理解的話,把它當成SOME應該能好理解一點,SOME 與 ANY 是等效的,即可以在SQL語句中把ANY換成SOME,效果一樣。可參考官方文檔:用 ANY、SOME 或 ALL 修改的比較運算符

🌟Another one: 查詢 計算機科學系中比計算機科學系 所有 學生年齡都 的學生姓名及年齡:

方法一:用ALL謂詞

SELECT Sname, Sage
FROM   Student
WHERE  Sage < ALL (SELECT Sage
                   FROM   Student
                   WHERE  Sdept = 'CS')
       AND Sdept <> 'CS';

方法二:用聚集函數(小於所有的,即小於其最小值)

SELECT Sname, Sage
FROM   Student
WHERE  Sage < 
           ( SELECT MIN(Sage)
             FROM   Student
             WHERE  Sdept = 'CS')
       AND Sdept <> 'CS';

在這裏插入圖片描述
採用ALL謂詞嵌套查詢的執行過程:
1)首先處理子查詢,找出CS系中所有學生的年齡,構成一個集合(20,19)
2)處理父查詢,找所有不是CS系年齡小於20和19(即小於最小值19)的學生

🔥小總結:ANY(或SOME),ALL謂詞與聚集函數、IN謂詞的等價轉換關係 :
在這裏插入圖片描述


本文到這裏也就結束啦,感謝你耐心地閱讀~😊,嵌套查詢中的重難點:帶有EXISTS謂詞的子查詢將會在下一篇中介紹 ~
這裏是一個想把學習過程記錄成博客分享給大家的undergraduate,請多關照🙏
咱們下期 ~
在這裏插入圖片描述

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