SQL如何合并查询结果并去重?UNION的使用场景 说到合并查询结果,很多人的第一反应就是UNION。但这里有个关键点需要先拎清楚:UNION 会自动去重并按第一列升序排序,而 UNION ALL 仅仅是简单地将结果集合并,没有任何额外的开销。实际上,绝大多数场景都应该优先考虑 UNION ALL,

说到合并查询结果,很多人的第一反应就是UNION。但这里有个关键点需要先拎清楚:UNION 会自动去重并按第一列升序排序,而 UNION ALL 仅仅是简单地将结果集合并,没有任何额外的开销。实际上,绝大多数场景都应该优先考虑 UNION ALL,因为它更快、也更可控。尤其是在业务逻辑已经确保没有重复数据,或者你打算后续自己进行去重操作时,强行使用 UNION 反而会拖慢查询速度。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
两者的核心差异,其实就体现在“自动处理”这四个字上。UNION 会默默帮你完成去重和排序,而 UNION ALL 则完全“撒手不管”,只负责合并。听起来UNION似乎更省心?但代价可不小。
UNION 默认按照第一个子查询的第一列进行升序排列。这既不是你SELECT的原始顺序,也未必符合你的业务逻辑顺序。想把几个查询用UNION串起来,可不是随便写写就行。它有几个硬性结构要求,不满足就会直接报错:
所有子查询的列数必须严格一致。
对应列的数据类型必须兼容(比如数值对数值,字符串对字符串)。
典型的错误信息大家可能都见过:ERROR: each UNION query must ha ve the same number of columns(列数不一致),或者ERROR: column “xxx” has type text but expression has type integer(类型不匹配)。
这里有几个实操细节值得注意:
AS别名是无效的。integer和bigint),但对于text和jsonb这类不兼容的类型,就必须显式转换,例如用col::text来对齐。NULL::text或某个默认值来占位补齐。那么,到底什么时候才真的需要UNION呢?答案是:只有当你确实需要“跨查询的语义去重”时。举个例子,你想找出“所有活跃用户”,而用户来源可能分散在注册用户表和第三方登录临时表里。这两个表的主键不同,但用户的邮箱可能重叠,而你的需求是每个邮箱只保留一条记录。
SELECT email, 'registered' AS source FROM users UNION SELECT email, 'social_login' AS source FROM social_logins;
UNION确保了相同的email只会出现一次,并且结果会自动按email升序排列。registered的记录),UNION就无能为力了。这时通常需要改用ROW_NUMBER() OVER (PARTITION BY email ORDER BY ...)配合公共表表达式(CTE)来实现。email IS NULL的记录,UNION在去重时会将这些NULL值视为相同,只保留一条。这是因为在去重逻辑中,NULL = NULL是成立的。当子查询本身就很复杂,或者你其实并不在意那些重复数据时,盲目使用UNION会让查询变得笨重。不妨优先考虑下面这些更灵活的方案:
UNION ALL + 外层SELECT DISTINCT:这样可以明确控制对哪些字段进行去重,避免数据库隐式排序带来的干扰。UNION ALL + GROUP BY:适合合并后还需要进行聚合统计的场景,比如按来源统计数量。UNION合并“有订单的用户”和“有收藏的用户”,其实可以尝试用OR条件,或者IN (SELECT ... UNION ALL SELECT ...)的子查询。在有合适索引支持的情况下,后者的性能往往更好。总而言之,UNION操作看似简单直接,但其背后的隐式排序和去重逻辑,常常在大数据量或复杂嵌套查询时突然暴露出性能问题。一个良好的习惯是,在查询上线前,务必使用EXPLAIN ANALYZE查看执行计划,留意其中是否出现了意料之外的Sort(排序)和Unique(去重)节点。这才是保证查询效率的关键所在。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述