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 | +-----+--------+-------+


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM