ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PostgreSQL 中的 UNION 与 UNION ALL:合并结果集时如何控制重复行

PostgreSQL 中的 UNION 与 UNION ALL:合并结果集时如何控制重复行 文档教程知识库【免费下载链接】til:memo: Today I Learned项目地址https://gitcode.com/gh_mirrors/ti/til点击查看免费下载在 PostgreSQL 中UNION与UNION ALL都是将两个查询或表的结果集纵向拼接成单个结果集的操作符两者的唯一区别在于是否保留重复行UNION会去重UNION ALL会保留全部重复行。本文以 til 仓库中 union-all-rows-including-duplicates.md 为核心结合仓库内其他 PostgreSQL 笔记完整演示这两种操作符的行为差异、适用场景并延伸到与之协同使用的VALUES、generate_series()、CTE 等集合构造技巧读完即可在实际查询中正确选择去重与否的合并方式。用 UNION 合并结果集默认去重两张表或两个查询的结果集可以用UNION操作符合并为一个结果集。合并时所有重复行都会被自动移除最终结果中每条记录只出现一次。下面的例子把两段generate_series(1,4)与generate_series(3,6)产生的序列合并select generate_series(1,4) union select generate_series(3,6) order by 1 asc; generate_series ----------------- 1 2 3 4 5 6 (6 rows)注意观察左半边包含 1、2、3、4右半边包含 3、4、5、6。尽管两侧各自都有 3 和 4但在UNION的结果里3 和 4 各只出现一次——这正是UNION的去重语义在起作用3和4这两条重复记录被折叠为单条。去重的实现代价UNION之所以能去重是因为 PostgreSQL 在执行时需要比较结果集里的每一行、剔除重复项。从实现原理看这通常意味着对合并后的结果做一次去重排序sort/unique 或 hash unique。因此当两侧结果集本身很大、且并不需要去重时UNION会产生不必要的计算开销。这也是引入UNION ALL的根本原因。用 UNION ALL 合并结果集保留全部重复行如果不想排除重复行改用UNION ALL。它在合并时不做任何去重两侧产生的每一行都会被原样保留在结果集中select generate_series(1,4) union all select generate_series(3,6) order by 1 asc; generate_series ----------------- 1 2 3 3 4 4 5 6 (8 rows)同样的两个序列这次得到 8 行而非 6 行3 和 4 各自出现了两次分别来自两侧输入。可以看到UNION ALL的结果正是两个结果集的简单拼接语义上等价于把两个查询的输出直接堆叠在一起。UNION 与 UNION ALL 行为对比行为UNIONUNION ALL重复行处理自动去重每条记录只出现一次原样保留重复行全部出现结果行数示例中 6 行示例中 8 行是否需要去重计算需要排序/哈希去重不需要典型适用场景需要唯一集合如合并两个查询的结果、求并集保留明细、拼接日志、分区表全量读取、性能敏感的合并两条核心经验需要数学意义上的并集不重复时用UNION需要物理上的拼接不丢行时用UNION ALL。实操要点两侧的列结构与可排序性使用UNION/UNION ALL时两侧查询必须满足两个前提列数相同两侧的select列表列数必须一致类型兼容对应位置的列类型需要能隐式统一PostgreSQL 会按需做类型调整必要时可显式cast。例如把UNION与仓库中 sets-with-the-values-command.md 介绍的VALUES命令结合可以非常紧凑地构造测试集合values (1), (2), (3) union all values (2), (3), (4); column1 --------- 1 2 3 2 3 4 (6 rows)VALUES本身就能生成一张临时表结构可以直接与UNION组合作为子查询、CTE 或insert ... select的一部分是构造并集/拼接场景测试数据的常用手段。搭配 ORDER BY 序号排序示例中使用了order by 1 asc这是 PostgreSQL 支持的输出列序号排序写法select列表中的每个表达式都有一个从 1 开始的索引可以直接在order by乃至group by中引用。仓库中的 use-argument-indexes.md 专门记录了这一技巧例如select id, updated_at from posts order by 2等价于按updated_at排序。在UNION场景下由于合并结果没有表别名用序号排序是最简洁可靠的方式可以避免为两侧子查询重复书写列名。延伸UNION 在 CTE 中的应用UNION不仅用于普通查询合并也是递归 CTEcommon table expression的语法基石。仓库中的 fizzbuzz-with-common-table-expressions.md 展示了典型的with recursive写法其递归分支正是用UNION连接初始行与递归生成的新行with recursive fizzbuzz (num,val) as ( select 0, union select (num 1), case when (num 1) % 15 0 then fizzbuzz when (num 1) % 5 0 then buzz when (num 1) % 3 0 then fizz else (num 1)::text end from fizzbuzz where num 100 ) select val from fizzbuzz where num 0;递归 CTE 要求递归项与终止项用UNION或UNION ALL连接其中UNION负责保证已经展开过的行不会被重复加入递归过程。理解UNION的去重语义有助于理解递归 CTE 为何能收敛反过来这也说明了UNION与UNION ALL的选择会直接影响最终结果的形状与行数。延伸用 generate_series() 快速验证合并行为本文示例大量使用generate_series(1,4)这类集合返回函数。仓库中的 insert-a-bunch-of-records-with-generate-series.md 说明了它的原理generate_series()会为参数区间内的每个值生成一行如1、2、3直到上界是造数据、写示例、验证集合语义时的利器。当你需要测试UNION/UNION ALL对大型结果集的去重行为时用它快速生成两段有重叠区间的序列即可复现本文全部示例。总结UNION合并结果集时自动去除重复行得到的是去重后的并集UNION ALL不做去重原样保留两侧全部行。是否需要去重直接决定了结果的形状示例中 6 行 vs 8 行与执行开销UNION需额外去重计算。合并两侧要求列数一致、类型兼容排序可借助输出列序号如order by 1简化书写。UNION是递归 CTE 的基础语法与VALUES、generate_series()配合可以快速构造各类集合测试场景。这篇笔记收录于 til 仓库的 postgres 目录 下并在 README.md 中建有索引相关的VALUES、generate_series()、参数序号与递归 CTE 技巧可分别参考 sets-with-the-values-command.md、insert-a-bunch-of-records-with-generate-series.md、use-argument-indexes.md 与 fizzbuzz-with-common-table-expressions.md。赞分享文档教程知识库【免费下载链接】til:memo: Today I Learned项目地址https://gitcode.com/gh_mirrors/ti/til点击查看免费下载相关推荐如何关掉 SystemInformer 悬停提示弹窗3 步快速指南如何关掉 SystemInformer 悬停提示弹窗3 步快速指南 你正在梳理进程树鼠标每划过一行就弹出一个提示小窗正好挡住你要看的数据。这是 Syste桌面应用调试器应用安全驱动开发深入解析 turf/union多边形并集Union合并的地理计算指南深入解析 turf/union多边形并集Union合并的地理计算指南 本指南以 Turf 项目 turf union 官方文档 https://lin数据分析给 AI 一个真实已登录的浏览器BrowserSkill 5 分钟上手指南给 AI 一个真实已登录的浏览器BrowserSkill 5 分钟上手指南 BrowserSkill 是一套面向 AI 浏览器自动化 的工具它由 bsk 命人工智能AI 应用AI 技能浏览器控制dsh-plugin上一篇告别僵硬交互Godot Engine实现VR手势抓取与投掷的5个关键步骤下一篇Docbox多语言代码示例功能详解支持7种编程语言的API文档创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表