在MySQL的日常数据统计工作中,经常会遇到需要同时满足去重和按条件筛选的计数需求,比如统计某个时间段内不同用户的活跃次数,或者统计不同分类下符合条件的唯一商品数量。COUNT(DISTINCT IF(...))就是一种可以高效实现这类需求的写法。

COUNT(DISTINCT IF(...))的基本语法
这种用法的核心逻辑是先用IF函数对数据进行条件判断,再将判断后的结果传给COUNT(DISTINCT)进行去重计数,基本语法结构如下:
-- 基本语法结构 SELECT COUNT(DISTINCT IF(条件表达式, 去重字段, NULL)) AS 统计别名 FROM 表名 [WHERE 其他筛选条件];
其中IF函数的第一个参数是条件表达式,当条件成立时返回需要去重的字段值,条件不成立时返回NULL,而COUNT(DISTINCT)会自动忽略NULL值,这样就实现了只对符合条件的数据进行去重计数的效果。
实际使用案例
假设我们有一个用户订单表user_order,表结构如下:
-- 建表语句
CREATE TABLE user_order (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL COMMENT '用户ID',
order_status TINYINT NOT NULL COMMENT '订单状态 1-待支付 2-已支付 3-已取消',
create_time DATETIME NOT NULL COMMENT '创建时间'
);
现在需要统计已支付订单(order_status=2)对应的不同用户数量,就可以使用COUNT(DISTINCT IF(...))实现:
-- 统计已支付订单的不同用户数 SELECT COUNT(DISTINCT IF(order_status = 2, user_id, NULL)) AS paid_user_count FROM user_order;
如果需要同时统计总的不同用户数和已支付的不同用户数,也可以在一个查询中完成:
-- 同时统计总用户数和已支付用户数
SELECT
COUNT(DISTINCT user_id) AS total_user_count,
COUNT(DISTINCT IF(order_status = 2, user_id, NULL)) AS paid_user_count
FROM user_order;
注意事项与替代方案
NULL值的处理逻辑
需要注意IF函数条件不成立时返回的是NULL,如果返回其他值比如0,那么COUNT(DISTINCT)会把0也当作有效值进行统计,导致结果错误,所以条件不成立时务必返回NULL。
性能相关说明
当表数据量较大时,COUNT(DISTINCT IF(...))可能会导致全表扫描,性能不如先筛选再统计的写法,上面的案例也可以写成如下形式:
-- 替代写法 先筛选已支付订单再统计去重用户数 SELECT COUNT(DISTINCT user_id) AS paid_user_count FROM user_order WHERE order_status = 2;
这种写法在数据量较大且有对应索引的情况下,性能会比COUNT(DISTINCT IF(...))更好,开发者可以根据实际场景选择合适的实现方式。
兼容性问题
COUNT(DISTINCT IF(...))是MySQL支持的写法,其他数据库比如PostgreSQL、SQL Server不支持这种语法,如果需要跨数据库兼容,建议使用CASE WHEN替代IF函数:
-- 使用CASE WHEN的兼容写法 SELECT COUNT(DISTINCT CASE WHEN order_status = 2 THEN user_id ELSE NULL END) AS paid_user_count FROM user_order;
MySQLCOUNT_DISTINCT_IF去重计数条件统计修改时间:2026-07-01 12:33:22