我們前邊說的都是單條查詢語句,其實多條查詢語句的查詢結果也可以被合併起來,這種將多個查詢的查詢結果合併起來的查詢方式稱為合併查詢
,或者組合查詢
。
查詢列表相同的情況
比如說下邊這兩條查詢語句:
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、n1
和m2、n2
是兩個不同的查詢列表,但是這兩個列組合中m1
和m2
都是整數型別的,n1
和n2
都是字串型別的,所以也可以把它們的查詢結果拼接到一起:
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核心的難度,讓學習曲線更平滑一點~