在SQL的实际业务分析中,按不同维度分组后统计各分组内不重复用户数是非常高频的需求,比如电商平台需要按商品类目统计购买过的独立用户数,运营团队需要按活动批次统计参与过的独立用户数,这类需求的核心就是正确使用COUNT DISTINCT完成去重计数。

COUNT DISTINCT基础用法
COUNT DISTINCT的作用是对指定列的非重复值进行计数,基础语法格式如下:
-- 统计全表不重复的用户数 SELECT COUNT(DISTINCT user_id) AS unique_user_count FROM user_action_table;
这里需要注意,COUNT DISTINCT会忽略列值为NULL的记录,不会将NULL计入统计结果。如果表中user_id存在NULL值,这些记录不会被算入最终的去重计数中。
分组场景下统计各分组不重复用户数
如果需要按某个字段分组,统计每个分组内的不重复用户数,只需要将GROUP BY和COUNT DISTINCT结合使用即可,语法逻辑是先按分组字段拆分数据,再在每个分组内执行去重计数。
假设我们有一张用户行为表user_action,表结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | int | 记录ID |
| user_id | int | 用户ID |
| category | varchar | 商品类目 |
| action_time | datetime | 行为时间 |
现在需要统计每个商品类目下的不重复购买用户数,对应的SQL语句如下:
SELECT
category,
COUNT(DISTINCT user_id) AS unique_user_count
FROM user_action
GROUP BY category;
执行这条语句后,会先按category字段将所有记录分成不同的组,每个组内再对user_id去重后计数,最终得到每个类目对应的独立用户数。
多字段去重统计技巧
有些场景下需要基于多个字段的组合去重,比如统计每个类目下,不同用户不同设备的去重数量,这时候可以把多个字段组合作为COUNT DISTINCT的参数。
假设user_action表新增了device_id字段,统计每个类目下用户和设备组合的不重复数量:
SELECT
category,
COUNT(DISTINCT user_id, device_id) AS unique_user_device_count
FROM user_action
GROUP BY category;
不过需要注意,部分数据库(比如MySQL)不支持COUNT DISTINCT传入多个参数,这种场景下可以用CONCAT函数将多个字段拼接后去重:
SELECT
category,
COUNT(DISTINCT CONCAT(user_id, '_', device_id)) AS unique_user_device_count
FROM user_action
GROUP BY category;
拼接的时候加入下划线是为了避免不同字段拼接后出现相同字符串的情况,比如user_id为12、device_id为3,和user_id为1、device_id为23,直接拼接都会得到123,加入分隔符就能避免这个问题。
常见注意事项
- COUNT DISTINCT只能对单个字段或者拼接后的单个表达式去重,不能直接统计多列的笛卡尔积去重,需要根据数据库特性选择对应实现方式。
- 如果分组字段本身存在NULL值,GROUP BY会将所有NULL值归为同一个分组,统计的时候也会对这个NULL分组计算去重用户数。
- 当数据量非常大的时候,COUNT DISTINCT的计算效率会比普通COUNT低,因为需要额外做去重操作,如果业务对精度要求不是极高,可以考虑用近似去重计数函数(比如HyperLogLog相关的函数)提升性能。
完整示例演示
我们插入一些测试数据,完整演示整个统计过程:
-- 创建测试表
CREATE TABLE user_action (
id INT,
user_id INT,
category VARCHAR(20),
device_id INT
);
-- 插入测试数据
INSERT INTO user_action VALUES
(1, 1001, '数码', 1),
(2, 1001, '数码', 1),
(3, 1001, '数码', 2),
(4, 1002, '数码', 1),
(5, 1002, '家居', 1),
(6, 1003, '家居', 1),
(7, 1003, '家居', 1);
-- 统计每个类目不重复用户数
SELECT
category,
COUNT(DISTINCT user_id) AS unique_user_count
FROM user_action
GROUP BY category;
上述语句执行后,数码类目的去重用户数是2(用户1001和1002),家居类目的去重用户数是1(用户1002和1003中只有1003属于家居类目),符合预期结果。
SQLCOUNT_DISTINCT分组统计去重计数修改时间:2026-07-11 22:30:23