PARTITION BY可对字符串、日期、布尔值分组,因只依赖值相等性判断;但SUM()、AVG()等数值函数用于非数值字段会报错,而COUNT(*)、ROW_NUMBER()、STRING_AGG()等则无问题。

PARTITION BY 能不能对字符串、日期、布尔值分组?
能,而且完全没问题。PARTITION BY 本身不关心字段类型,只看值是否“相等”——字符串按字典序比对,日期按时间点比对,布尔值就两个值 TRUE/FALSE,照样可分组。关键不是类型,而是你后续用的窗口函数是否支持该类型输入。
哪些窗口函数在非数值字段上容易出错?
常见坑是误用需要数值上下文的函数,比如 SUM()、AVG()、STDDEV() 直接套在字符串上会报错:ERROR: function sum(text) does not exist。但 COUNT()、ROW_NUMBER()、RANK()、FIRST_VALUE()、STRING_AGG()(PostgreSQL)或 GROUP_CONCAT()(MySQL)就没问题。
-
COUNT(*)或COUNT(1):统计每组行数,最安全 -
ROW_NUMBER() OVER (PARTITION BY status ORDER BY created_at):按状态分组后编号,status是字符串也 OK -
FIRST_VALUE(name) OVER (PARTITION BY category ORDER BY score DESC):每类里取最高分的人名,category是字符串,name也是字符串 - 想拼接同组字符串?PostgreSQL 用
STRING_AGG(name, ', '),MySQL 用GROUP_CONCAT(name),别硬套SUM(name)
ORDER BY 在 PARTITION BY 后为什么经常被忽略?
很多同学只写 PARTITION BY region,但没加 ORDER BY,结果 ROW_NUMBER() 或 LEAD() 返回顺序不稳定——尤其当数据来自不同索引或并发写入时。数据库不保证无 ORDER BY 的窗口函数执行顺序。
实操建议:
- 只要用了
ROW_NUMBER()、LAG()、NTILE()等依赖顺序的函数,OVER里必须显式写ORDER BY - 如果分组字段本身就是业务主序(比如按
order_date分组再按created_at排),那就得双层排序:PARTITION BY order_date ORDER BY created_at, id - 注意:MySQL 8.0+ 和 PostgreSQL 支持,但旧版 MySQL(5.7)不支持窗口函数,别在那儿试
PARTITION BY
NULL 值在 PARTITION BY 中怎么算一组?
所有主流 SQL 引擎(PostgreSQL、SQL Server、Oracle、MySQL 8.0+)都把 NULL 视为相同值,即所有 NULL 会落在同一个分区内。这不是 bug,是 SQL 标准行为。
如果你不想让 NULL 自成一组,常用做法是预处理:
- 用
COALESCE(category, 'UNKNOWN')替换空值再分组 - 或用
CASE WHEN category IS NULL THEN 'MISSING' ELSE category END构造确定值 - 直接过滤:
WHERE category IS NOT NULL,前提是业务允许丢弃空值
不处理的话,COUNT(*) 会如实统计含 NULL 的组,但 STRING_AGG() 可能跳过 NULL(取决于数据库,默认通常忽略),这点容易漏查。

















