rollup生成的null是汇总标记而非数据缺失,grouping()函数可精准区分:返回1表示rollup自动生成,0表示真实数据;需配合with rollup使用,避免用is null误判。

ROLLUP生成的NULL和真实NULL在语义上完全不同
ROLLUP会在聚合结果中自动插入汇总行,这些行对应维度列的位置会填入NULL作为占位符——但它不是数据缺失,而是“这一层不参与分组”的标记。而表中原始字段存的NULL表示该记录确实没有值。两者混在一起查,很容易误判业务含义。
用GROUPING()函数精准识别ROLLUP占位NULL
GROUPING()是专为解决这个问题设计的函数:它接收一个分组列名,返回1表示该值由ROLLUP(或CUBE/GROUPING SETS)自动生成,返回0表示来自真实数据。
-
GROUPING(city)= 1 → 这行的city是ROLLUP加的汇总行,不是某条记录真没填城市 -
GROUPING(city)= 0 → 这行city来自原始数据,哪怕值本身是NULL - 必须配合
GROUP BY ... WITH ROLLUP使用,单独查无意义
示例:
SELECT GROUPING(city) AS is_rollup_city, city, SUM(sales) AS total_sales FROM orders GROUP BY city WITH ROLLUP;
结果中,is_rollup_city = 1的行,其city列的NULL就是ROLLUP生成的;其余行即使city为NULL,也属于原始数据空值。
避免用IS NULL直接过滤ROLLUP行
直接写WHERE city IS NULL会把真实缺失城市的数据和ROLLUP汇总行一起干掉,丢失两类不同语义的信息。
- 想只保留真实NULL:加条件
WHERE city IS NULL AND GROUPING(city) = 0 - 想只保留ROLLUP行:用
HAVING GROUPING(city) = 1(注意必须用HAVING,因为GROUPING()是聚合后计算) - MySQL 8.0+支持
GROUPING(),但旧版MySQL需用IFNULL(city, 'ALL')之类变通,无法真正区分
真实NULL和ROLLUP NULL在排序与显示时行为一致但含义相反
两者在ORDER BY里都默认排最前(除非显式用NULLS LAST),视觉上无法分辨。这也是为什么不能依赖位置或外观做判断——必须靠GROUPING()函数打标。
最容易被忽略的是:当多列ROLLUP(如GROUP BY a, b WITH ROLLUP)时,GROUPING(a)和GROUPING(b)可能同时为1(全汇总行),也可能一者为1一者为0(仅a汇总、b保留明细),得逐列判断,不能只看某一个NULL就下结论。










