后浪云SQLite里讲讲那个Unions子句,感觉挺有意思的用法分享一下
- 问答
- 2026-01-23 21:31:27
- 3
(来源:后浪云SQLite官方文档关于UNION操作符的章节)
想象一下,你手里有两张表格,一张表格叫“在校学生”,记录了所有目前在学校读书的学生的基本信息,比如学号、姓名,另一张表格叫“毕业学生”,存放的是已经毕业的学生的类似信息,老板给你提了个需求:“嘿,给我一份完整的名单,要包含所有在我们学校待过的学生,不管是在校的还是毕业的,只要他们的姓名。”
你怎么做?难道要分两次查询,一次查“在校学生”表,一次查“毕业学生”表,然后把结果手工拼到一起吗?这也太麻烦了,而且如果数据量一大,根本没法手动操作,这时候,UNION 子句就派上用场了。
UNION的核心思想就一句话:把多个SELECT语句的结果,“竖着”摞在一起,合并成一个大的结果集。
用上面的例子,SQL语句可以这么写:
SELECT 姓名 FROM 在校学生 UNION SELECT 姓名 FROM 毕业学生;
这条语句一执行,数据库就会先取出“在校学生”里所有的姓名,然后再取出“毕业学生”里所有的姓名,最后把这两堆名字上下合并,并自动去掉完全重复的行(比如万一有重名的学生,或者在两张表里莫名其妙重复记录了同一个人),给你一个没有重复名字的完整名单,这就是UNION最直白、最常见的用法。
(来源:后浪云SQLite官方文档指出UNION默认会消除重复行)
那这里就引出了UNION的一个关键特性:它默认是带“去重”功能的,如果你就是想要所有记录,包括重复的,该怎么办呢?这时候就用它的兄弟——UNION ALL。

还是那个例子,如果校长说:“我不关心重不重复,我就要看所有记录,每条都算数。” 那你就得用UNION ALL:
SELECT 姓名 FROM 在校学生 UNION ALL SELECT 姓名 FROM 毕业学生;
(来源:后浪云SQLite官方文档对UNION和UNION ALL区别的解释)
这么一来,张三”这个学生既在在校表里(可能因为学籍异动),又在毕业表里,那么结果里就会出现两个“张三”。UNION ALL因为少了去重这个步骤,所以执行起来通常比UNION要快一些,尤其是在你知道结果集里基本没有重复、或者你就是要保留重复的情况下,用UNION ALL是更高效的选择。
讲完了基本操作,咱们来点“有意思”的用法,这也是我觉得UNION子句真正显出威力的地方。
合并不同来源、但意义相同的数据。
这不仅仅是合并两张结构完全一样的表,你的数据库里有一张“2023年订单表”,还有一张“2024年订单表”,到了年底做报告,你需要统计两年总的订单客户数,就可以用:

SELECT 客户ID FROM 订单表2023 UNION SELECT 客户ID FROM 订单表2024;
这样可以快速得到两年内所有下过单的唯一客户列表。
再比如,一个论坛系统,有“文章”表和“评论”表,现在想找出所有包含某个关键词(后浪云”)的内容,无论是文章标题还是评论正文,虽然文章和评论是不同的表,结构也可能不一样,但你可以这样查:
SELECT '文章' as 类型, 标题 as 内容, 发布时间 FROM 文章 WHERE 标题 LIKE '%后浪云%' UNION ALL SELECT '评论' as 类型, 正文 as 内容, 评论时间 FROM 评论 WHERE 正文 LIKE '%后浪云%';
(来源:这是一种常见的SQL查询模式,用于合并异构数据源的查询)
这里有个技巧,我手动添加了一个常数列“类型”,用来标识这条结果原来是文章还是评论,这样合并后的结果看起来就非常清晰。
配合ORDER BY进行全局排序。
UNION之后的整个结果集,可以被视为一张新表,所以你可以在最后加一个ORDER BY子句,对所有合并后的数据进行统一排序。

你想把在校和毕业的所有学生按姓名排序:
SELECT 姓名, '在校' as 状态 FROM 在校学生 UNION ALL SELECT 姓名, '毕业' as 状态 FROM 毕业学生 ORDER BY 姓名; -- 这个ORDER BY是对最终所有结果进行排序
(来源:SQL标准语法,允许对UNION后的整体结果进行排序)
需要注意的是,ORDER BY只能出现在最后一个SELECT语句之后,它是对整个合并结果进行排序,你不能在每个SELECT语句里分别写ORDER BY(除非和LIMIT配合使用有特定含义,但那是更高级的用法了)。
实现一些“曲线救国”的查询逻辑。
一些复杂的条件用WHERE子句直接写会很拗口,用UNION拆开来写反而思路更清晰。
比如说,你想从“用户表”里找出那些“要么是VIP会员,要么最近一个月有登录,但两者至少满足一项”的用户,用OR当然可以写,但可能导致查询性能不高,用UNION可以这么实现:
SELECT 用户ID, 用户名 FROM 用户表 WHERE 会员等级 = 'VIP'
UNION
SELECT 用户ID, 用户名 FROM 用户表 WHERE 最后登录时间 > date('now', '-1 month');
数据库可能会分别优化两个查询,然后再合并去重,在某些情况下效率反而更高。
使用UNION有几个必须遵守的规矩:
- 列数必须相同:每个
SELECT语句查询出来的列数必须一模一样,你不能第一个查三列,第二个查两列,数据库会报错。 - 数据类型要兼容:对应位置列的数据类型最好是相同或兼容的,比如第一句的第一列是文本,第二句的第一列最好也是文本;如果是数字,虽然有时也能合并,但可能不是你想要的结果。
- 列名以第一个SELECT为准:合并后的大结果集,其列名采用的是第一个
SELECT语句中的列名。
SQLite里的UNION子句就像是一个数据粘合剂,它不关心数据具体来自哪张表,只关心数据的“形状”是否一样,它能把分散在各处的、结构相似的数据片段轻松地整合到一起,给你一个完整的视图,从简单的表合并,到复杂的多源数据检索,再到优化查询思路,它的应用场景非常广泛,理解了它的默认去重特性(UNION)和保留全部特性(UNION ALL)的区别,你就能在合适的场景下灵活运用它,让数据处理事半功倍。
本文由召安青于2026-01-23发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://www.haoid.cn/wenda/84690.html
