partition by 多列必须用逗号分隔,不可加括号或and;其逻辑是先按第一列分组,再在每组内按第二列细分,等价于group by多列分组但不压缩行数。

PARTITION BY 多列写法:括号里直接用逗号分隔
SQL 中 PARTITION BY 本身不支持“组合分组”这种说法——它就是天然支持多列的,只要把列名用逗号隔开就行,不需要嵌套或额外语法。很多人卡在写成 PARTITION BY (col1, col2),这是错的:PARTITION BY 后面**不能加括号**,括号只用于函数调用或子查询。
常见错误现象:ERROR: syntax error at or near "(" 或结果分组数异常(比如本该按地区+年份分,却按单列分了)。
-
PARTITION BY region, year✅ 正确写法 -
PARTITION BY (region, year)❌ 触发语法错误(PostgreSQL/Oracle/SQL Server 均不认) -
PARTITION BY region AND year❌ 逻辑运算符不能用于分组
窗口函数里多列 PARTITION BY 的实际效果
多列 PARTITION BY 等价于“先按第一列分,再在每个子组内按第二列细分”,和 GROUP BY a, b 的分组逻辑一致,但注意:窗口函数不会压缩行数,每行仍保留原始数据,只是计算范围被限定在该多列组合的唯一值组内。
使用场景:比如算每个城市每年销售额占该城市总销售额的比例,就得 PARTITION BY city, year 来算年度局部占比;如果只写 PARTITION BY city,就会混入其他年份数据。
示例:
SELECT city, year, sales, SUM(sales) OVER (PARTITION BY city, year) AS yearly_city_total, ROUND(100.0 * sales / SUM(sales) OVER (PARTITION BY city, year), 2) AS pct_of_yearly_city FROM sales_data;
ORDER BY 和 PARTITION BY 共存时的优先级与陷阱
当 PARTITION BY 多列 + ORDER BY 出现在同一窗口定义中,ORDER BY 是在每个分区内部排序,不是全局排序。容易忽略的关键点是:如果 ORDER BY 列不在 PARTITION BY 列中,会导致“相同分区键但排序不稳定”,尤其影响 ROW_NUMBER()、LAG() 等依赖顺序的函数。
- 安全做法:确保
ORDER BY的列能唯一标识分区内的行(比如加上主键或时间戳) - 危险写法:
PARTITION BY dept, team ORDER BY salary—— 同薪多人时,ROW_NUMBER()结果可能每次执行不一致 - 性能影响:多列
PARTITION BY会增加哈希分组开销,列越多、基数越大,内存占用越高;必要时加复合索引加速(如(dept, team, updated_at))
不同数据库对多列 PARTITION BY 的兼容性差异
主流数据库(PostgreSQL、SQL Server、Oracle、BigQuery、Trino)都完全支持多列 PARTITION BY,写法统一。但 MySQL 8.0+ 才支持窗口函数,且早期版本(8.0.0–8.0.16)在某些嵌套窗口场景下有 bug,比如 SUM() OVER (PARTITION BY a, b ORDER BY c) 可能返回空值。
- MySQL 用户务必升级到 8.0.17+,并测试
EXPLAIN ANALYZE输出确认分区是否生效 - SQLite 目前(3.45)仍不支持窗口函数,别试
- ClickHouse 支持,但要求
PARTITION BY列必须是表的排序键前缀,否则报NOT_FOUND
真正复杂的地方往往不在语法,而在于你是否意识到:多列 PARTITION BY 的组合值必须在数据中真实存在且非空——任意一列是 NULL,整组就被视为一个独立分区(不是被跳过),这点常导致统计偏差却难以察觉。











