新特性解讀 | MySQL 8.0 對 UNION 的改進

愛可生雲資料庫發表於2022-03-07

作者:張偉

愛可生北京分公司 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);

四、參考文件:

https://dev.mysql.com/doc/ref...

相關文章