mysql中union關(guān)鍵字的實現(xiàn)示例
MySQL 的 UNION 用于合并兩個或多個 SELECT 語句的結(jié)果集,并自動去除重復(fù)行(相當(dāng)于對結(jié)果集執(zhí)行 DISTINCT)。
1. 基本語法與核心規(guī)則
SELECT column1, column2 FROM table1 UNION [ALL | DISTINCT] SELECT column1, column2 FROM table2;
強(qiáng)制性規(guī)則:
- 列數(shù)必須相同:兩個 SELECT 返回的列數(shù)必須一致
- 數(shù)據(jù)類型兼容:對應(yīng)位置的列類型不必完全相同,但必須可隱式轉(zhuǎn)換(如 INT 和 DECIMAL)
- 列名繼承:結(jié)果集的列名取自第一個 SELECT 語句
- ORDER BY 位置:只能放在最后一個 SELECT 之后,且排序依據(jù)必須是第一個 SELECT 的列名或別名
2. UNION vs UNION ALL
| 特性 | UNION (DISTINCT) | UNION ALL |
|---|---|---|
| 去重 | 自動去重,行唯一 | 保留所有行,包括重復(fù) |
| 性能 | 需要臨時表+哈希排序去重,較慢 | 直接追加結(jié)果,極快 |
| 使用場景 | 必須確保唯一性時 | 確定無重復(fù)或需要保留重復(fù)時 |
性能建議:除非業(yè)務(wù)需要去重,否則優(yōu)先使用 UNION ALL。去重操作需要創(chuàng)建臨時表、哈希比較和額外排序,大數(shù)據(jù)量時性能差距巨大。
3. 實際應(yīng)用場景
場景 A:合并相似結(jié)構(gòu)表(如分表)
-- 查詢 2023 和 2024 年的訂單(假設(shè)按年分表) 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ù)補(bǔ)全與兜底查詢
-- 先查緩存表,若無結(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. 進(jìn)階用法
帶排序和分頁
(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)化器忽略。
混合聚合與明細(xì)
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)化要點(diǎn)
- 索引利用:每個 SELECT 獨(dú)立使用索引,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+ 對非相關(guān)子查詢的 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(看你之前關(guān)注過 Django 源碼),可以這樣使用:
from django.db.models import Q
# QuerySet.union() 默認(rèn)使用 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() 會強(qiáng)制轉(zhuǎn)換為 SQL 的 UNION,且 QuerySet 被求值后返回的是列表而非 QuerySet,無法繼續(xù)鏈?zhǔn)竭^濾。
總結(jié):UNION ALL 是合并結(jié)果集的高性能首選,UNION (DISTINCT) 僅在需要去重時使用。始終確保子查詢列數(shù)一致,并在應(yīng)用層處理復(fù)雜的排序邏輯。
到此這篇關(guān)于mysql中union關(guān)鍵字的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)mysql union關(guān)鍵字內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL存儲表情時報錯:java.sql.SQLException: Incorrect string value:‘
這篇文章主要給大家介紹了關(guān)于MySQL存儲表情時報錯:java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\xA9\x0D\x0A...'的解決方法,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧。2018-04-04
MySQL的Replace into 與Insert into on duplicate key update真正的不同
今天聽同事介紹oracle到mysql的數(shù)據(jù)migration,他用了Insert into ..... on duplicate key update ...,我當(dāng)時就想怎么不用Replace呢,于是回來就仔細(xì)查了下,它們果然還是有區(qū)別的2014-02-02
MySQL使用pt-table-sync修復(fù)主從數(shù)據(jù)一致性問題
在 MySQL 主從架構(gòu)中,數(shù)據(jù)一致性是運(yùn)維的核心訴求,大事務(wù)中斷、誤操作等都可能導(dǎo)致主從數(shù)據(jù)偏差,今天分享一款 Percona Toolkit 旗下的神器pt-table-sync,通過實戰(zhàn)案例教大家高效修復(fù)主從數(shù)據(jù)不一致問題,需要的朋友可以參考下2026-04-04
infobright導(dǎo)入數(shù)據(jù)遇到特殊字符報錯的解決方法
這篇文章主要介紹了infobright導(dǎo)入數(shù)據(jù)遇到特殊字符報錯的解決方法,Infobright是開源的MySQL數(shù)據(jù)倉庫解決方案,需要的朋友可以參考下2014-07-07

