union天然支持合并与自动去重,前提是各select列数相同、对应列类型兼容、不可缺列,且按整行完全一致(含null)去重,结果默认按第一列升序排列。

直接用 UNION 就行,它天然支持合并 + 自动去重。
UNION 去重的前提条件
两个查询必须满足结构一致性,否则会报错:
- 列数完全相同:比如第一个 SELECT 返回 3 列,第二个也必须返回 3 列
- 对应列类型兼容:数值对数值(如 INT 和 BIGINT 可隐式转换),字符串对字符串(如 VARCHAR 和 TEXT 通常可转);但 TEXT 和 JSONB 这类不兼容的,得显式转,例如
col::text - 不能缺列:如果某查询少一列,要用
NULL::text或默认值补位,不能留空 - 列名以第一个 SELECT 为准:后面子句里的
AS alias不生效,想统一字段名,只能在第一个里定义
UNION 去重的实际效果
它按整行内容判断重复——只要所有列值完全一致(包括 NULL),就只保留一行:
- 例如两个查询都查出
(1, 'Alice', 25),最终结果只出现一次 - 注意:
NULL = NULL在 UNION 去重中成立,所以多条(1, NULL, 25)也会被合并为一条 - 结果默认按第一列升序排,不是原始顺序,也不是你写的 SELECT 顺序
一个典型示例
查「所有活跃用户邮箱」,来源可能是注册表和第三方登录表,两者结构不同但都有 email 字段:
SELECT email, 'registered' AS source FROM usersUNION
SELECT email, 'social_login' AS source FROM social_logins;
即使某个邮箱同时存在于两张表,结果中也只出现一次,并按 email 升序排列。
什么时候不该硬套 UNION?
如果只是拼数据、不真正在意重复,或后续还要做聚合/排序,UNION 反而拖慢性能:
- 去重要建临时表、排序、逐行比对,数据量超 10 万行时明显变慢
- 想控制“保留哪个重复项”(比如优先取注册用户而非社交登录),UNION 无法做到,得换
ROW_NUMBER() OVER (PARTITION BY email ORDER BY ...) - 需要保留原始顺序或自定义排序,应在最外层加
ORDER BY,且只能按第一个 SELECT 的列名或序号写










