mysql中union關鍵字的實現(xiàn)示例
MySQL 的 UNION 用于合并兩個或多個 SELECT 語句的結(jié)果集,并自動去除重復行(相當于對結(jié)果集執(zhí)行 DISTINCT)。
1. 基本語法與核心規(guī)則
SELECT column1, column2 FROM table1 UNION [ALL | DISTINCT] SELECT column1, column2 FROM table2;
強制性規(guī)則:
- 列數(shù)必須相同:兩個 SELECT 返回的列數(shù)必須一致
- 數(shù)據(jù)類型兼容:對應位置的列類型不必完全相同,但必須可隱式轉(zhuǎn)換(如 INT 和 DECIMAL)
- 列名繼承:結(jié)果集的列名取自第一個 SELECT 語句
- ORDER BY 位置:只能放在最后一個 SELECT 之后,且排序依據(jù)必須是第一個 SELECT 的列名或別名
2. UNION vs UNION ALL
| 特性 | UNION (DISTINCT) | UNION ALL |
|---|---|---|
| 去重 | 自動去重,行唯一 | 保留所有行,包括重復 |
| 性能 | 需要臨時表+哈希排序去重,較慢 | 直接追加結(jié)果,極快 |
| 使用場景 | 必須確保唯一性時 | 確定無重復或需要保留重復時 |
性能建議:除非業(yè)務需要去重,否則優(yōu)先使用 UNION ALL。去重操作需要創(chuàng)建臨時表、哈希比較和額外排序,大數(shù)據(jù)量時性能差距巨大。
3. 實際應用場景
場景 A:合并相似結(jié)構(gòu)表(如分表)
-- 查詢 2023 和 2024 年的訂單(假設按年分表) SELECT order_id, amount, created_at FROM orders_2023 UNION ALL SELECT order_id, amount, created_at FROM orders_2024 ORDER BY created_at DESC LIMIT 20;
場景 B:多維度統(tǒng)計報表
SELECT 'VIP用戶' as user_type, COUNT(*) as cnt FROM users WHERE level >= 8 UNION ALL SELECT '普通用戶', COUNT(*) FROM users WHERE level BETWEEN 1 AND 7 UNION ALL SELECT '訪客', COUNT(*) FROM users WHERE level = 0;
場景 C:數(shù)據(jù)補全與兜底查詢
-- 先查緩存表,若無結(jié)果再查主表(常見于配置表) SELECT config_value FROM config_cache WHERE config_key = 'site_name' UNION ALL SELECT config_value FROM config WHERE config_key = 'site_name' LIMIT 1;
4. 進階用法
帶排序和分頁
(SELECT id, name FROM products WHERE category = 'A' ORDER BY price DESC LIMIT 10) UNION ALL (SELECT id, name FROM products WHERE category = 'B' ORDER BY price DESC LIMIT 10) ORDER BY price DESC LIMIT 10;
注意:子查詢中的 ORDER BY 必須配合 LIMIT 才生效,否則會被優(yōu)化器忽略。
混合聚合與明細
SELECT city, sales_amount, NULL as detail FROM sales_summary UNION ALL SELECT city, amount, CONCAT(product_name, ':', quantity) FROM sales_detail;
5. 性能優(yōu)化要點
- 索引利用:每個 SELECT 獨立使用索引,UNION 本身不走索引
- 減少數(shù)據(jù)集:在子查詢中先
WHERE過濾,避免傳遞大量數(shù)據(jù)到 UNION 層 - 避免臨時表寫入:
UNION DISTINCT會創(chuàng)建內(nèi)存臨時表(或磁盤臨時表,若過大),可通過SET tmp_table_size調(diào)優(yōu) - 并行執(zhí)行:MySQL 8.0.19+ 對非相關子查詢的 UNION 可能啟用并行查詢
6. 常見陷阱
-- ? 錯誤:列數(shù)不匹配 SELECT id, name FROM t1 UNION SELECT id FROM t2; -- ERROR 1222 -- ? 錯誤:ORDER BY 位置錯誤 SELECT * FROM t1 ORDER BY id UNION SELECT * FROM t2; -- ERROR 1221 -- ? 正確寫法 SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY id; -- 使用第一個 SELECT 的列名排序
7. Django ORM 中的 UNION
如果你在使用 Django(看你之前關注過 Django 源碼),可以這樣使用:
from django.db.models import Q
# QuerySet.union() 默認使用 UNION ALL
qs1 = User.objects.filter(status='active').values('name', 'email')
qs2 = User.objects.filter(is_staff=True).values('name', 'email')
# UNION ALL
combined = qs1.union(qs2, all=True)
# UNION (去重)
combined_distinct = qs1.union(qs2) # 或 all=False
注意:Django 的 union() 會強制轉(zhuǎn)換為 SQL 的 UNION,且 QuerySet 被求值后返回的是列表而非 QuerySet,無法繼續(xù)鏈式過濾。
總結(jié):UNION ALL 是合并結(jié)果集的高性能首選,UNION (DISTINCT) 僅在需要去重時使用。始終確保子查詢列數(shù)一致,并在應用層處理復雜的排序邏輯。
到此這篇關于mysql中union關鍵字的實現(xiàn)示例的文章就介紹到這了,更多相關mysql union關鍵字內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Mysql 5.7從節(jié)點配置多線程主從復制的方法詳解
這篇文章主要介紹了Mysql 5.7從節(jié)點配置多線程主從復制的相關資料,文中介紹的非常詳細,對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。2017-03-03
phpmyadmin出現(xiàn)#2003服務器無響應解決方法小結(jié)
出現(xiàn)登陸phpmyadmin出現(xiàn) #2003 - 服務器沒有響應最先想到的是你的mysql服務器是不是停止了檢查一下,如果是mysql服務器停止服務了重啟就可以解決問題了2012-04-04
VSCODE連接MySQL數(shù)據(jù)庫服務圖文教程
最近做網(wǎng)頁碰到連接數(shù)據(jù)庫的問題,上網(wǎng)查了挺久終于搞明白了,下面這篇文章主要給大家介紹了關于VSCODE連接MySQL數(shù)據(jù)庫服務的相關資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2023-06-06

