作者:張偉
愛可生北京分公司 DBA 團隊成員,負責 MySQL 日常問題處理和 DMP 產品維護。喜愛技術和開源資料庫,喜愛運動、讀書、電影,花草樹木。
本文來源:原創投稿
*愛可生開源社群出品,原創內容未經授權不得隨意使用,轉載請聯絡小編並註明來源。
一、UNION 的作用:
UNION 可以將多個 SELECT 查詢語句的結果合併成一個結果集,在MySQL 8.0 中又增添了一些新的功能,我們一起來看下。
二、UNION 操作符的花樣展示:
1、溫故
- Union 必須由兩條或以上的 SELECT 語句組成,才能使用 Union 連線。
- Union 中每個查詢必須包含相同數量的列或者聚合函式,列名或者別名需要一致。
- 列資料型別必須相容,即可以進行隱式型別轉換,但可能會出現 SQL 效能問題,建議資料型別相同。
舉例如下:
create table t1 (id int, name varchar(20));
insert into t1 values(1,"愛可生"),(2,"開源"),(3,"社群"),(5,"MySQL"),(4,"張");
create table t2 (id int, name varchar(20));
insert into t2 values(3,"中國"),(11,"技術"),(15,"開源"),(2,"社群"),(1,"偉大");
mysql> select id from t1;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 5 |
| 4 |
+------+
5 rows in set (0.00 sec)
mysql> select id from t2;
+------+
| id |
+------+
| 3 |
| 11 |
| 15 |
| 2 |
| 1 |
+------+
5 rows in set (0.00 sec)
// DISTINCT: 刪除結果集中重複的資料。
mysql> select id from t1 union distinct select id from t2;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 5 |
| 4 |
| 11 |
| 15 |
+------+
7 rows in set (0.00 sec)
// 預設情況下 UNION 操作符已經刪除了重複資料,所以 DISTINCT 修飾符對結果沒啥影響。
mysql> select id from t1 union select id from t2;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 5 |
| 4 |
| 11 |
| 15 |
+------+
7 rows in set (0.00 sec)
// ALL: 返回包括重複資料在內的所有結果集。
mysql> select id from t1 union all select id from t2;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 5 |
| 4 |
| 3 |
| 11 |
| 15 |
| 2 |
| 1 |
+------+
10 rows in set (0.00 sec)
使用 Union 組合查詢時,只能使用一條 order by 子句對結果集進行排序,而且必須出現在最後一條出現的 SELECT 語句之後。因為 Union 不允許對於部分結果集進行排序,只能針對最終檢索出來的結果集進行排序。
注意:由於在多表組合查詢時候,可能表欄位並不相同。所以在對於結果集排序的時候需要使用檢索出來的共同欄位。檢索的欄位 id 必須存在於結果集中。
舉例如下:
2、知新
- 從 MySQL 8.0.19 版本開始,不僅在 SELECT 語句中,也可以在 TABLE 或 VALUES 語句中使用 UNION,只要可以使用等效的 SELECT 語句。
- 可以在 TABLE 中使用ORDER BY和LIMIT,但不支援WHERE子句。
- ORDER BY 不能使用包含 表名.列名 的引用。相反,在第一個 SELECT 語句中提供列別名,並在 ORDER BY 中引用別名。
- 如果要排序的列具有別名,ORDER BY 子句必須引用別名,而不是列名。
舉例如下:
// 新增 table 語句的使用,由於取的是全表,對於單一欄位的去重就不便使用了
mysql> table t1 union select * from t2;
+------+-----------+
| id | name |
+------+-----------+
| 1 | 愛可生 |
| 2 | 開源 |
| 3 | 社群 |
| 5 | MySQL |
| 4 | 張 |
| 3 | 中國 |
| 11 | 技術 |
| 15 | 開源 |
| 2 | 社群 |
| 1 | 偉大 |
+------+-----------+
10 rows in set (0.01 sec)
// 新增 values 語句的使用,但會導致欄位名失效
mysql> values row(15,'開源') union select * from t2;
+----------+----------+
| column_0 | column_1 |
+----------+----------+
| 15 | 開源 |
| 3 | 中國 |
| 11 | 技術 |
| 2 | 社群 |
| 1 | 偉大 |
+----------+----------+
5 rows in set (0.01 sec)
// 使用table 語句和values 語句的結合
mysql> values row(15,'開源'),row(13,'北京') union table t2;
+----------+----------+
| column_0 | column_1 |
+----------+----------+
| 15 | 開源 |
| 13 | 北京 |
| 3 | 中國 |
| 11 | 技術 |
| 2 | 社群 |
| 1 | 偉大 |
+----------+----------+
6 rows in set (0.01 sec)
// 如果定義欄位名可以使用以下方法
mysql > select * from (values row(15,'開源'),row(13,'北京')) AS t(c1,c2) union table t2;
+------+--------+
| c1 | c2 |
+------+--------+
| 15 | 開源 |
| 13 | 北京 |
| 3 | 中國 |
| 11 | 技術 |
| 2 | 社群 |
| 1 | 偉大 |
+------+--------+
6 rows in set (0.02 sec)
三、對比 MySQL 8.0 和 5.7 對 union 的處理
在 MySQL 8.0 中,對 SELECT 和 UNION 的解析器規則被重構進而變得更加一致,且減少了重複。
與 MySQL 5.7 相比,某些語句可能需要重寫:
- 對比標準 SQL , NATURAL JOIN 允許一個可選的 INNER 關鍵字(NATURAL INNER JOIN)。
- 對比標準 SQL ,可以使用不帶括號的 Right-deep JOIN(例如,…JOIN…JOIN…ON…ON)。
- 與其他 INNER JOIN 類似,STRAIGHT_JOIN 現在允許 USING 子句。
- 解析器接受查詢表示式周圍的括號。例如:(SELECT ... UNION SELECT…)。
- 以前只允許在子查詢中使用 union 的左巢狀,現在允許頂層語句中使用。如:(SELECT 1 UNION SELECT 1) UNION SELECT 1 ;
- 包含鎖定子句的 SELECT 語句必須使用括號。例如:SELECT 1 FOR UPDATE UNION SELECT 1 FOR UPDATE; 變更為 (SELECT 1 FOR UPDATE) UNION (SELECT 1 FOR UPDATE);