MySQL基礎筆記(三) 複雜查詢

所謂複雜查詢,指涉及多個表、具有嵌套等複雜結構的查詢。這裏簡要介紹典型的幾種複雜查詢格式。

一、連接查詢

連接是區別關係與非關係系統的最重要的標誌。通過連接運算符可以實現多個表查詢。連接查詢主要包括內連接、外連接等。

假設有StudentGrade兩個表如下:

+-----+--------+-------+     +-----+------------+--------+
| sID | sName  | sDept |     | gID | gCourse    | gScore |
+-----+--------+-------+     +-----+------------+--------+
|   1 | Paul   | CS    |     |   1 | Math       |     87 |
|   2 | Oliver | MS    |     |   2 | English    |     95 |
|   3 | Jack   | SE    |     |   3 | Physics    |     76 |
|   4 | Robin  | CS    |     |   7 | Philosophy |     76 |
+-----+--------+-------+     +-----+------------+--------+

1.1 內連接

內連接(INNER JOIN)使用比較運算符進行表間列數據的比較操作,並列出這些表中與連接條件相匹配的數據行,組合成新的記錄。

當比較操作符是=時,稱爲等值連接:

SELECT * FROM Student INNER JOIN Grade ON Student.sID = Grade.gID;

等價於

SELECT * FROM Student,Grade WHERE Student.sID = Grade.gID;

結果如下:

+-----+--------+-------+-----+---------+--------+
| sID | sName  | sDept | gID | gCourse | gScore |
+-----+--------+-------+-----+---------+--------+
|   1 | Paul   | CS    |   1 | Math    |     87 |
|   2 | Oliver | MS    |   2 | English |     95 |
|   3 | Jack   | SE    |   3 | Physics |     76 |
+-----+--------+-------+-----+---------+--------+

可以看出,在內連接查詢中,只有滿足條件的記錄才能出現在結果關係中。

1.2 外連接

與內連接不同的是,外連接返回的查詢結果集中不僅包含符合連接條件的行,而且還包括左表(左連接)、右表(右連接)或兩個表(全外連接)中的所有數據行。

1.2.1 左連接

LEFT JOIN(左連接),即LEFT OUTER JOIN,返回左表的全部記錄,即使右表中沒有對應匹配記錄。

SELECT * FROM Student LEFT JOIN Grade ON Student.sID = Grade.gID;

結果如下:

+-----+--------+-------+------+---------+--------+
| sID | sName  | sDept | gID  | gCourse | gScore |
+-----+--------+-------+------+---------+--------+
|   1 | Paul   | CS    |    1 | Math    |     87 |
|   2 | Oliver | MS    |    2 | English |     95 |
|   3 | Jack   | SE    |    3 | Physics |     76 |
|   4 | Robin  | CS    | NULL | NULL    |   NULL |
+-----+--------+-------+------+---------+--------+

1.2.2 右連接

RIGHT JOIN(右連接),即RIGHT OUTER JOIN,返回右表的全部記錄,即使左表中沒有對應匹配記錄。

SELECT * FROM Student RIGHT JOIN Grade ON Student.sID = Grade.gID;

結果如下:

+------+--------+-------+-----+------------+--------+
| sID  | sName  | sDept | gID | gCourse    | gScore |
+------+--------+-------+-----+------------+--------+
|    1 | Paul   | CS    |   1 | Math       |     87 |
|    2 | Oliver | MS    |   2 | English    |     95 |
|    3 | Jack   | SE    |   3 | Physics    |     76 |
| NULL | NULL   | NULL  |   7 | Philosophy |     76 |
+------+--------+-------+-----+------------+--------+

1.2.3 全連接

FULL JOIN(全連接),即FULL OUTER JOIN,返回左表、右表的全部記錄,即使沒有對應的匹配記錄。

**注意:**MySQL不支持FULL JOIN,不過可以通過UNION關鍵字來合併 LEFT JOIN 與 RIGHT JOIN來模擬。

SELECT * FROM Student LEFT JOIN Grade ON Student.sID = Grade.gID
UNION
SELECT * FROM Student RIGHT JOIN Grade ON Student.sID = Grade.gID;

結果如下:

+------+--------+-------+------+------------+--------+
| sID  | sName  | sDept | gID  | gCourse    | gScore |
+------+--------+-------+------+------------+--------+
|    1 | Paul   | CS    |    1 | Math       |     87 |
|    2 | Oliver | MS    |    2 | English    |     95 |
|    3 | Jack   | SE    |    3 | Physics    |     76 |
|    4 | Robin  | CS    | NULL | NULL       |   NULL |
| NULL | NULL   | NULL  |    7 | Philosophy |     76 |
+------+--------+-------+------+------------+--------+

另外,如果在一個連接查詢中涉及到的兩個表是同一個表,這種查詢稱爲自連接查詢。爲了防止產生二義性,自連接查詢中通常對錶使用別名。


二、子查詢

子查詢是指一個查詢語句嵌套在另一個查詢語句內部的查詢。在 SELECT 子句中先計算子查詢,子查詢結果作爲外層另一個查詢的過濾條件。

子查詢中常用的操作符有ANYSOMEALLEXISTSIN,也可以使用比較運算符。子查詢可以添加到 SELECT、UPDATE 和 DELETE 語句中,而且可以進行多層嵌套。

2.1 在條件表達式中產生標量的子查詢

SELECT *
FROM score
WHERE id = (SELECT event_id
            FROM event
            WHERE date='2015-07-01'
            AND type='Q'); 

所謂標量,就是單個屬性的一個原子值。當子查詢出現在 WHERE 子句中的比較運算符(= ,>, >= ,< , <= ,<>)的右邊,其輸出結果應該只有一個纔對。很容易理解,如果返回多條結果,就無法進行比較,系統就會報錯。

又如:

SELECT * FROM teacher WHERE birth = MIN(birth);  /*錯誤*/

這個查詢是錯的!因爲MySQL不允許在子句裏面使用統計函數,所以改用子查詢:

SELECT *
FROM teacher
WHERE birth = (SELECT MIN(birth)
               FROM teacher);

2.2 在條件表達式中產生集合的子查詢

如果子查詢的輸出是一個結果集合,可以通過 ANY、ALL、IN 進行比較。

2.2.1 ANY與SOME

ANYSOME關鍵字是同義詞,表示滿足其中任一條件。它們允許創建一個表達式對子查詢的返回結果集進行比較:

SELECT num1
FROM t1
WHERE num1 > ANY(SELECT num2 
                 FROM t2);

上面的子查詢返回 t2 的 num2 列,然後將 t1 中的 num1 值與之進行比較,只要大於 num2 的任何一個值,即爲符合查詢條件的結果。

等價於:

SELECT num1
FROM t1
WHERE num1 > SOME(SELECT num2 
                  FROM t2);

2.2.2 ALL

ANY/SOME不同,使用ALL時需要同時滿足所有內層查詢的條件。

SELECT num1
FROM t1
WHERE num1 > ALL(SELECT num2 
                 FROM t2);

上面的子查詢還是返回 t2 的 num2 列,然後將 t1 中的 num1 值與之進行比較。但是隻有大於所有 num2 值的 num1 纔是符合查詢條件的結果。

2.2.3 IN

IN關鍵字後接一個子查詢,若在子查詢結果集中,返回true,否則返回false。與之相對的是NOT IN

SELECT num1
FROM t1
WHERE num1 IN (SELECT num2 
               FROM t2);

2.3 在條件表達式中測試空/非空的子查詢

EXISTS關鍵字後接一個任意的子查詢,系統對子查詢進行運算以判斷它是否返回行。

  • 若至少返回一行,那麼 EXISTS 的結果爲 true,此時外層查詢語句將進行查詢;
  • 若沒有返回任何行,那麼 EXISTS 的結果爲 false,此時外層語句將不進行查詢。
SELECT sName
FROM Student
WHERE EXISTS (SELECT * 
              FROM Grade 
              WHERE gScore < 60);

EXISTSNOT EXISTS的結果只取決於是否會返回行,而不取決於這些行的內容。

2.4 關聯子查詢

一般的子查詢只計算一次,其結果用於外層查詢。但關聯子查詢需要計算多次。

子查詢中使用了主查詢中的某些字段,主查詢每掃描一行都要執行一次子查詢,這種子查詢稱爲關聯子查詢(Correlated Subquery)

SELECT sName
FROM Student
WHERE '450' NOT IN (SELECT courseID
                    FROM Course
                    WHERE sID = Student.sID);

上面的子查詢中使用了 Student 表的 sID 字段。對於 Student 表中每一個 sID 都會執行一次子查詢。

2.5 FROM子句中的子查詢

子查詢可以用括號括起來作爲一個關係,從而出現在 FROM 列表中。由於子查詢的結果關係沒有正式的名字,故必須給它取一個別名。

SELECT *
FROM Grade,
    (SELECT * FROM Student WHERE sDept='CS')x
WHERE x.sID=Grade.gID;

x 就是子查詢的結果關係的別名。


三、合併查詢結果

利用UNIONUNION ALL關鍵字,可以將多個 SELECT 語句的結果組合成單個結果集。合併時,兩個表對應的列數和數據類型必須相同。

  • UNION:合併查詢結果時,刪除重複的記錄,返回的行都是唯一的。
  • UNION ALL:合併查詢結果時,不刪除重複行。

3.1 UNION ALL

SELECT * FROM Student 
UNION ALL
SELECT * FROM Student;

結果如下:

+-----+--------+-------+
| sID | sName  | sDept |
+-----+--------+-------+
|   1 | Paul   | CS    |
|   2 | Oliver | MS    |
|   3 | Jack   | SE    |
|   4 | Robin  | CS    |
|   1 | Paul   | CS    |
|   2 | Oliver | MS    |
|   3 | Jack   | SE    |
|   4 | Robin  | CS    |
+-----+--------+-------+

3.2 UNION

SELECT * FROM Student 
UNION
SELECT * FROM Student;

結果如下:

+-----+--------+-------+
| sID | sName  | sDept |
+-----+--------+-------+
|   1 | Paul   | CS    |
|   2 | Oliver | MS    |
|   3 | Jack   | SE    |
|   4 | Robin  | CS    |
+-----+--------+-------+







個人站點:http://songlee24.github.com

發佈了111 篇原創文章 · 獲贊 250 · 訪問量 82萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章