当前位置: 首页
数据库
SQL中PARTITION BY和GROUP BY有什么区别_窗口函数原理解析

SQL中PARTITION BY和GROUP BY有什么区别_窗口函数原理解析

热心网友 时间:2026-04-25
转载

GROUP BY压缩行数生成聚合结果,PARTITION BY保留原始行数仅附加计算值;前者用于统计报表,后者用于明细分析并支持窗口函数排序、排名等操作。

SQL中PARTITION BY和GROUP BY有什么区别_窗口函数原理解析

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

GROUP BY 会压缩行数,PARTITION BY 不改变行数

这可以说是两者最核心、最根本的区别。简单来说,GROUP BY 之后,你得到的结果集行数,会小于或等于原始数据中分组键的去重数量——数据被“压缩”了。而 PARTITION BY 则完全不同,它必须配合窗口函数(也就是 OVER())使用,其作用是在原有每一行数据上“附加”一个计算值,原始数据一条都不会少。

这里有个新手常踩的坑:有人会写 SELECT name, salary, A VG(salary) FROM emp GROUP BY name,本意是想查看每个人的工资以及他所在部门的平均工资。但实际上,这要么会报错,要么会产生逻辑错误。原因在于,A VG(salary) 是一个聚合值,name 是分组键,但查询中没有说明如何处理那些既非分组键、又非聚合函数的字段(比如这里的 salary 字段)。如果换成窗口函数的写法:A VG(salary) OVER (PARTITION BY dept_id),问题就迎刃而解了。这个写法不仅语法正确,还能在结果中保留每个人的 namesalarydept_id 等全部明细信息。

  • 记住一个铁律:GROUP BY 之后,SELECT 列表里只能出现两种东西:分组字段本身,或者包裹了聚合函数(如 SUM、A VG、COUNT)的表达式。
  • PARTITION BY 则出现在 OVER() 子句内部,它并不参与 SQL 标准执行顺序中的“分组”阶段。它的计算发生在 SELECT 产出结果之后,是一种“叠加”式的计算。
  • 从性能角度看:在大表上使用 GROUP BY,通常会触发哈希分组或排序操作,内存和磁盘的开销比较明显。而 PARTITION BY 在窗口计算阶段进行分区扫描,如果分区粒度很粗(比如整个表作为一个分区),那性能可能退化成全表遍历。

PARTITION BY 必须和 OVER() 一起用,不能单独存在

这一点必须明确:PARTITION BY 不是一个可以独立存在的 SQL 语句,它仅仅是 OVER() 子句的一个组成部分。如果你试图脱离 OVER() 单独使用它,比如写成 SELECT * FROM t PARTITION BY col,数据库会直接报错,告诉你语法非法。

来看一个典型的使用场景:如果你想为每个部门内的员工,按照薪资从高到低进行编号,同时还要保留所有原始字段,该怎么做?

SELECT emp_id, name, dept_id, salary,
       ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rn
FROM employees;

在这段代码里,PARTITION BY dept_id 定义了“在每个部门内部进行独立编号”这个范围,ORDER BY salary DESC 指定了编号的顺序规则,而 ROW_NUMBER() 则是执行编号操作的窗口函数本身。

  • 漏写 OVER() 是初学者最高频的语法错误之一,常见的报错信息是 “missing window specification” 或类似提示。
  • PARTITION BY 子句可以为空(即不写),此时整个结果集会被视为一个大的分区。例如,COUNT(*) OVER() 会计算整个查询结果的总行数。
  • 多个 PARTITION BY 字段用逗号分隔,其语义等同于多维分组。比如 PARTITION BY region, year 表示先按地区分区,再在每个地区内按年份分区。

GROUP BY 的执行时机早于 PARTITION BY

理解 SQL 的执行顺序至关重要。在标准的 SQL 执行流程中,GROUP BY 发生在 HA VING 子句之前,但在 SELECT 列表确定之后。而包含 PARTITION BY 的窗口函数,其计算时机要晚得多——它是在最终的 SELECT 列确定之后才进行的。这意味着,窗口函数“看到”的数据,是已经经过 WHERE 过滤、GROUP BY 聚合(如果用了的话)之后的数据。

由此引出一个关键结论:你无法在同一个查询中,既用 GROUP BY 把数据压缩成汇总行,又指望 PARTITION BY 能对原始的、未聚合的明细行进行分区计算。这两者是互斥的。

  • 如果想同时得到部门汇总数据和员工明细数据怎么办?通常需要两个查询通过 UNION ALL 组合,或者使用公共表表达式(CTE)分开处理。
  • 在已经使用了 GROUP BY 的查询里嵌套窗口函数时,PARTITION BY 所分区的对象是聚合后的行,而非原始明细行。例如,SELECT dept_id, COUNT(*) cnt, SUM(cnt) OVER (PARTITION BY dept_id) 这个查询中,每个部门的 cnt 已经是一个单独的聚合值,再对它按部门分区求和已经没有实际意义。
  • 数据库兼容性需要注意:Oracle 和 PostgreSQL 等数据库支持在 GROUP BY 之后使用窗口函数,但 MySQL 直到 8.0 版本才完全支持这种组合。在旧版 MySQL(如 5.7)中尝试这么做会直接报错。

别把 PARTITION BY 当成 GROUP BY 的替代品

有些人看到 PARTITION BY 也能“按某列分开计算”,就试图用它来绕过 GROUP BYSELECT 列表的严格限制。比如,用 SELECT name, salary, A VG(salary) OVER (PARTITION BY dept_id) 来代替 GROUP BY dept_id。语法上这确实能执行,但两者的语义天差地别:前者返回所有员工的记录,并在每个人旁边附加其所在部门的平均工资;后者只返回每个部门一行数据,包含部门ID和该部门的平均工资。

选择依据其实很简单:问问自己,最终想要的是「汇总报告」还是「带有标记的明细」?

  • 如果你的目标是生成统计报表、进行数据聚合后导出 → 毫不犹豫地选择 GROUP BY
  • 如果你的需求是做排名、计算累计求和、进行前后行比较,或者在保留所有明细的同时增加统计列 → 那么 PARTITION BY 配合窗口函数就是你的最佳工具。
  • 当需要混合使用时,务必先确认数据库版本是否支持,尤其要警惕 MySQL 5.7 及更早版本完全不支持窗口函数。

最后,还有一个真正容易被忽略的细节,它源于执行顺序带来的隐性依赖:当你的查询变得复杂,同时包含了 WHERE 过滤、GROUP BY 聚合和窗口函数时,PARTITION BY 所“看到”的数据,已经是经过层层过滤和聚合之后的结果了——它不会,也不可能回溯到最原始的表数据。这一点在编写复杂分析查询时,必须时刻牢记。

来源:https://www.php.cn/faq/2347918.html

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
Redis统计独立用户访问量的四种方案

Redis统计独立用户访问量的四种方案

在网站分析、广告监测、推荐系统等场景中,独立用户访问量(UV,Unique Visitor)是一个核心指标。UV 的关键在于去重——同一个用户多次访问只计一次。 Redis 提供了多种数据结构来高效实现 UV 统计,各有优劣。本文将详细对比 Set、Bitmap、HyperLogLog、incr +

时间:2026-04-25 14:04
MySQL设置数据格为空白或NULL问题及解决

MySQL设置数据格为空白或NULL问题及解决

前言 昨天规划一个项目,需要建个数据库。过程中遇到个小需求:想把某些数据格设为“空白”。一开始觉得,直接传个空字符串进去不就行了?但转念一想,这真的能算“空白”吗? 我最初尝试了更“偷懒”的办法——直接不传值(现在回头看,这思路确实有点问题)。结果,PHPMyAdmin立刻弹出了提示:“这行需要三个

时间:2026-04-25 14:04
PostgreSQL开发怎么找回历史执行记录_Navicat特有功能实操

PostgreSQL开发怎么找回历史执行记录_Navicat特有功能实操

Na vicat 的历史 SQL 记录仅保存在本地客户端的 History 子目录中,为加密二进制格式,不上传服务器、不写入数据库;PostgreSQL 服务端需主动启用 pg_stat_statements 或 log_statement 才能获取统计性或全量执行信息。 Na vicat 的历史

时间:2026-04-25 14:04
为什么SQL关联后的Count数值不对_区分Count星号与Count字段

为什么SQL关联后的Count数值不对_区分Count星号与Count字段

为什么SQL关联后的Count数值不对?区分Count星号与Count字段 在数据统计和分析工作中,COUNT函数的使用频率极高,但也是最容易踩坑的地方之一。你是否遇到过这样的困惑:明明是同一次查询,用COUNT(*)和COUNT(字段名)得出的结果却天差地别?或者在关联查询之后,总数莫名其妙地膨胀

时间:2026-04-25 14:04
mysql如何在一个语句中完成先查后增_INSERT INTO SELECT写法

mysql如何在一个语句中完成先查后增_INSERT INTO SELECT写法

MySQL INSERT INTO SELECT:一个语句搞定“查完就插”,避开这些坑才算真会了 想把一张表的数据查出来,立刻塞进另一张表?一条INSERT INTO SELECT语句就能搞定,省去中间步骤,效率直接拉满。不过,这语法看着简单,踩坑的人可不少。最常见的报错就是字段对不上,或者

时间:2026-04-25 14:04
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜
热门教程
更多
  • 游戏攻略
  • 安卓教程
  • 苹果教程
  • 电脑教程