支持非数值字段的聚合函数有count(*)、count(列名)、max(列名)、min(列名)、group_concat(mysql)、string_agg(postgresql);其中count统计行数,max/min按类型规则比较,sum/avg仅限数值型。

非数值型字段(如字符串、日期、布尔值)完全能参与聚合统计,但必须选对函数——COUNT、STRING_AGG、GROUP_CONCAT、MAX/MIN 可以直接用;SUM、AVG 会报错。
哪些聚合函数支持非数值字段?
关键不是字段类型,而是函数是否接受该类型输入。主流数据库(PostgreSQL、MySQL 8.0+、SQL Server、Oracle)行为一致:
-
COUNT(*)和COUNT(列名):统计行数,无视类型,NULL值被跳过(COUNT(*)除外) -
MAX(列名)/MIN(列名):对字符串按字典序、对日期按时间先后、对布尔值按FALSETRUE 比较,全部合法 -
STRING_AGG(列名, ', ')(PostgreSQL)或GROUP_CONCAT(列名)(MySQL):拼接同组字符串,最常用也最实用 -
ARRAY_AGG(列名)(PostgreSQL)或JSON_ARRAYAGG(列名)(MySQL 5.7+):生成数组/JSON结构,适合后续程序解析
反例:SUM(status) 或 AVG(category) 在任何引擎里都会触发类似 ERROR: function sum(text) does not exist 的错误。
PARTITION BY + 非数值字段分组时,ORDER BY 为什么不能省?
当用 ROW_NUMBER()、LEAD()、NTILE() 这类依赖顺序的窗口函数时,仅写 PARTITION BY category 是危险的——数据库不保证无 ORDER BY 时的行序。尤其在并发写入、索引缺失或执行计划变化时,结果可能每次都不一样。
正确写法必须显式声明排序依据:
SELECT order_id, category, ROW_NUMBER() OVER (PARTITION BY category ORDER BY order_date DESC, order_id) AS rn FROM orders;
如果业务上“同一分类内谁先谁后”本身没定义,那就别用 ROW_NUMBER(),改用 COUNT(*) 或 STRING_AGG() 更稳妥。
NULL 值在分组和聚合中怎么处理?
所有标准 SQL 引擎都把所有 NULL 视为相等,因此 PARTITION BY category 会让所有 category IS NULL 的行自动归入同一组。这不是 bug,是 SQL 标准行为。
如果你不想让空值抱团,有三个实际可选路径:
- 预处理替换:
PARTITION BY COALESCE(category, 'UNKNOWN') - 条件构造:
PARTITION BY CASE WHEN category IS NULL THEN 'MISSING' ELSE category END - 直接过滤:
WHERE category IS NOT NULL(前提是业务允许丢弃空值)
注意:COUNT(category) 会跳过 NULL,但 COUNT(*) 不会;STRING_AGG(category, ', ') 在 PostgreSQL 中默认跳过 NULL,MySQL 的 GROUP_CONCAT() 同理——这点容易被忽略,导致拼接结果漏项。










