MySQL入門系列:查詢簡介(七)之組合查詢

小孩子4919發表於2019-03-14

我們前邊說的都是單條查詢語句,其實多條查詢語句的查詢結果也可以被合併起來,這種將多個查詢的查詢結果合併起來的查詢方式稱為合併查詢,或者組合查詢

查詢列表相同的情況

比如說下邊這兩條查詢語句:

mysql> SELECT m1, n1 FROM t1 WHERE m1 < 2;
+------+------+
| m1   | n1   |
+------+------+
|    1 | a    |
+------+------+
1 row in set (0.00 sec)

mysql> SELECT m1, n1 FROM t1 WHERE m1 > 2;
+------+------+
| m1   | n1   |
+------+------+
|    3 | c    |
+------+------+
1 row in set (0.00 sec)

mysql>
複製程式碼

這兩個查詢語句可以使用UNION來合併起來:

mysql> SELECT m1, n1 FROM t1 WHERE m1 < 2 UNION SELECT m1, n1 FROM t1 WHERE m1 > 2;
+------+------+
| m1   | n1   |
+------+------+
|    1 | a    |
|    3 | c    |
+------+------+
2 rows in set (0.01 sec)

mysql>
複製程式碼

多個查詢語句也直接用UNION來合併起來:

mysql> SELECT m1, n1 FROM t1 WHERE m1 < 2 UNION SELECT m1, n1 FROM t1 WHERE m1 > 2 UNION SELECT m1, n1 FROM t1 WHERE m1 = 2;
+------+------+
| m1   | n1   |
+------+------+
|    1 | a    |
|    3 | c    |
|    2 | b    |
+------+------+
3 rows in set (0.00 sec)

mysql>
複製程式碼

當然,這種將對於查詢列表相同的多個查詢合併起來的情況可以通過修改WHERE子句來達到目的,比如上邊的查詢可以替換為:

SELECT m1, n1 FROM t1 WHERE m1 < 2 OR m1 > 2 OR m1 = 2;
複製程式碼

具體使用哪種查詢方式還需要分析這兩種查詢的效能消耗,我們後邊在優化查詢時會詳細嘮叨的。

查詢列表不同的情況

對於查詢列表不同的情況就只能用UNION來合併多個查詢了,比方說下邊這兩個查詢:

mysql> SELECT m1, n1 FROM t1 WHERE m1 < 2;
+------+------+
| m1   | n1   |
+------+------+
|    1 | a    |
+------+------+
1 row in set (0.00 sec)

mysql> SELECT m2, n2 FROM t2 WHERE m2 > 2;
+------+------+
| m2   | n2   |
+------+------+
|    3 | c    |
|    4 | d    |
+------+------+
2 rows in set (0.00 sec)

mysql>
複製程式碼

第一個查詢是從t1表中查詢m1, n1這兩個列的資料,第二個查詢是從t2表中查詢m2, n2這兩個列的資料。雖然m1、n1m2、n2是兩個不同的查詢列表,但是這兩個列組合中m1m2都是整數型別的,n1n2都是字串型別的,所以也可以把它們的查詢結果拼接到一起:

mysql> SELECT m1, n1 FROM t1 WHERE m1 < 2 UNION SELECT m2, n2 FROM t2 WHERE m2 > 2;
+------+------+
| m1   | n1   |
+------+------+
|    1 | a    |
|    3 | c    |
|    4 | d    |
+------+------+
3 rows in set (0.01 sec)

mysql>
複製程式碼

不過需要注意,查詢的結果集中顯示的列名將以第一個查詢中的列名為準。雖然幾個查詢的資料都可以被放入同一個結果集,但是結果集總是要有一個列名的吧,所以就規定採用第一個查詢中的列名,上邊的例子就採用了第一個查詢中的m1, n1作為結果集的列名。

包含或取消重複的行

我們看下邊這兩個查詢:

mysql> SELECT m1, n1 FROM t1;
+------+------+
| m1   | n1   |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
+------+------+
3 rows in set (0.00 sec)

mysql> SELECT m2, n2 FROM t2;
+------+------+
| m2   | n2   |
+------+------+
|    2 | b    |
|    3 | c    |
|    4 | d    |
+------+------+
3 rows in set (0.00 sec)

mysql>
複製程式碼

很顯然,t1表裡有3條記錄,t2表裡有3條記錄,我們把它們合併起來看一下:

mysql> SELECT m1, n1 FROM t1 UNION SELECT m2, n2 FROM t2;
+------+------+
| m1   | n1   |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|    4 | d    |
+------+------+
4 rows in set (0.00 sec)

mysql>
複製程式碼

為什麼合併後的結果只剩下了4條記錄呢?因為使用UNION來合併多個查詢的記錄會預設過濾掉重複的記錄。由於t1表和t2表都有(2, b)、(3, c)這兩條記錄,所以合併後的結果集就把他倆去重了。如果我們想要保留重複記錄,可以使用UNION ALL來連線多個查詢:

mysql> SELECT m1, n1 FROM t1 UNION ALL SELECT m2, n2 FROM t2;
+------+------+
| m1   | n1   |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|    2 | b    |
|    3 | c    |
|    4 | d    |
+------+------+
6 rows in set (0.00 sec)

mysql>
複製程式碼

對組合查詢結果排序

合併查詢會把各個查詢的結果彙總到一塊,我們只能對最後總的結果集進行排序,而不能分別對各個查詢進行排序。由於最後的結果集展示的列名是第一個查詢中給定的列名,所以ORDER BY子句中指定的排序列也必須是第一個查詢中給定的列名,比如這樣:

mysql> SELECT m1, n1 FROM t1 UNION SELECT m2, n2 FROM t2 ORDER BY m1 DESC;
+------+------+
| m1   | n1   |
+------+------+
|    4 | d    |
|    3 | c    |
|    2 | b    |
|    1 | a    |
+------+------+
4 rows in set (0.00 sec)

mysql>
複製程式碼

如果我們分別對各個查詢進行排序會報錯的:

mysql> SELECT m1, n1 FROM t1 ORDER BY m1 DESC UNION SELECT m2, n2 FROM t2 ORDER BY m2;
ERROR 1221 (HY000): Incorrect usage of UNION and ORDER BY
mysql>
複製程式碼

合併查詢注意事項

  • 被合併的各個查詢的查詢物件個數必須相同

    不能一個查詢的結果集中有1個列,另一個卻有2個列,這會報錯的:

    mysql> SELECT m1 FROM t1 UNION SELECT m2, n2 FROM t2;
    ERROR 1222 (21000): The used SELECT statements have a different number of columns
    mysql>
    複製程式碼
  • 查詢的結果集中顯示的列名將以第一個查詢中的列名為準

  • 各個查詢語句中的查詢列表的型別相容就可以(也就是說不必完全相同)

    mysql> select m1 from t1 union select n2 from t2;
    +------+
    | m1   |
    +------+
    | 1    |
    | 2    |
    | 3    |
    | b    |
    | c    |
    | d    |
    +------+
    6 rows in set (0.00 sec)
    
    mysql>
    複製程式碼

    m1的型別是整數型別,n2是字串型別,如果把這兩個查詢用UNION合併起來,那麼整個結果集的的列的型別將變成字串型別。雖然這種型別轉換是支援的,但是將不同型別的資料放在一個列中容易造成混亂,還是建議大家將各個查詢的查詢列表置為相同的型別

小冊

本系列專欄都是MySQL入門知識,想看進階知識可以到小冊中檢視:《MySQL是怎樣執行的:從根兒上理解MySQL》的連結 。小冊的內容主要是從小白的角度出發,用比較通俗的語言講解關於MySQL進階的一些核心概念,比如記錄、索引、頁面、表空間、查詢優化、事務和鎖等,總共的字數大約是三四十萬字,配有上百幅原創插圖。主要是想降低普通程式設計師學習MySQL核心的難度,讓學習曲線更平滑一點~

MySQL入門系列:查詢簡介(七)之組合查詢

相關文章