先查原始数据分布,确认数据质量是否达标:用COUNT()与COUNT(字段)对比识别NULL;频次统计暴露空值、大小写、空格等问题;多字段分组需验证组合唯一性;数值聚合必须内层CAST防溢出;JOIN后需COALESCE再CAST;COUNT()与COUNT(字段)语义不同,不可互换。

先查原始数据分布,别急着改SQL
聚合结果不准,第一反应不该是调函数或加条件,而是确认参与计算的数据本身是否符合预期。很多“错误”其实是数据质量问题被放大了。
- 用
SELECT COUNT(*)和SELECT COUNT(字段)对比,看是否有大量NULL被跳过 - 对关键字段做频次统计:
SELECT 字段, COUNT(*) FROM 表 GROUP BY 字段 ORDER BY COUNT(*) DESC LIMIT 10,检查是否存在异常值(如空字符串、'0'、'null' 字面量) - 若字段本该非空但实际有
NULL,用WHERE 字段 IS NULL单独查出来,确认是录入问题还是业务逻辑允许 - 注意大小写、前后空格、全角/半角字符——
TRIM(UPPER(字段))再分组可能暴露出隐藏的重复
GROUP BY 字段是否真正唯一?
结果行数比预期少,大概率是分组键没真正区分数据。MySQL 和 PostgreSQL 在严格模式下会报错,但宽松模式下会静默返回任意一行值,极易误导。
- 检查
GROUP BY字段类型:整数型 ID 和字符串型 ID 混用时,CAST(user_id AS CHAR)才能保证语义一致 -
NULL值在分组中被合并为一组,而WHERE 字段 IS NULL可能漏掉这部分,需单独验证 - 多字段分组时,确认所有字段都参与了业务维度定义,比如按
date分组却忽略timezone,跨时区数据会被压平 - 用
SELECT COUNT(DISTINCT CONCAT(a,b,c))验证组合键唯一性,比肉眼数GROUP BY结果更可靠
聚合函数内部是否溢出或隐式转换?
数值型聚合(尤其是 SUM、AVG)结果明显偏小、为负数或报错,十有八九是中间计算溢出了——外层 CAST 无效,必须从源头控制类型。
- 错误写法:
CAST(SUM(amount) AS BIGINT)—— 加法已在INT范围内溢出,再转无意义 - 正确写法:
SUM(CAST(amount AS BIGINT))或SUM(CAST(amount AS DECIMAL(18,2))) -
LEFT JOIN后聚合,amount可能为NULL,先COALESCE(amount, 0)再CAST,避免类型推导失败 -
HAVING条件里也要同步处理类型:HAVING SUM(CAST(amount AS BIGINT)) > 1000000000,否则比较仍走原类型
COUNT(*) 和 COUNT(字段) 差异暴露一致性问题
这两个函数不是“差不多”,而是代表完全不同的统计口径。用错一个,整个分析逻辑就偏了。
-
COUNT(*) = COUNT(字段)是判断该字段是否全非空的最简布尔校验 - 想查“哪些订单没填收货地址”,写
HAVING COUNT(address) = 0不对,应写HAVING COUNT(*) > COUNT(address) -
LEFT JOIN场景下,COUNT(右表.id)返回匹配行数(含 0),COUNT(*)返回左表行数,二者差值就是关联缺失数 - 做占比计算时,
COUNT(flag)/COUNT(*)在 MySQL/PostgreSQL 中默认整除,必须写成COUNT(flag) * 1.0 / COUNT(*)或CAST(COUNT(flag) AS DECIMAL)/COUNT(*)
真正容易被忽略的,是同一个字段在不同子句(SELECT、HAVING、ORDER BY、变量赋值)中可能触发多次独立的类型推导。漏掉任何一个环节,溢出或截断就还在那里。

















