不能直接用DISTINCT与COUNT、SUM等聚合函数混用(COUNT(DISTINCT)除外);需用GROUP BY实现去重后聚合,或通过子查询/CTE先去重再聚合。

DISTINCT 能不能直接和 COUNT、SUM 一起用?
不能直接写 COUNT(DISTINCT) 以外的聚合函数搭配 DISTINCT —— 比如 SUM(DISTINCT col) 在大多数数据库(PostgreSQL、SQL Server、Oracle)里是合法的,但 MySQL 8.0 之前根本不支持,MySQL 8.0+ 虽然语法通过,实际行为可能和预期不符(比如对浮点数去重后求和易出精度偏差)。更关键的是,SELECT DISTINCT col1, SUM(col2) 这种写法会报错:非聚合字段和聚合函数混用,且没加 GROUP BY。
想算“每个唯一值对应的聚合结果”,必须用 GROUP BY
真正能同时体现“去重逻辑”和“聚合计算”的方式,是把要去重的字段放进 GROUP BY,再对其他字段做聚合。例如:统计每个用户(去重)的订单总金额:
SELECT user_id, SUM(order_amount) AS total FROM orders GROUP BY user_id;
这里 user_id 天然去重(每组只出现一次),SUM() 在每组内计算。这不是靠 DISTINCT 关键字实现的去重,而是靠分组机制保证的语义等价。
-
GROUP BY字段必须出现在SELECT列表中(除非用聚合函数包裹) - 如果想对多个字段组合去重后再聚合(比如每个
(country, product)对的销量),就把它们全写进GROUP BY - 别试图在
GROUP BY后加DISTINCT——语法错误,也无意义
COUNT(DISTINCT col) 是唯一被广泛支持的“DISTINCT + 聚合”特例
这是 SQL 标准明确支持、所有主流数据库都兼容的写法,用于统计某列不重复值的个数:
SELECT COUNT(DISTINCT user_id) FROM orders;
注意几个常见陷阱:
-
COUNT(DISTINCT col1, col2)在 PostgreSQL 和 SQL Server 中合法(统计组合去重数),但在 MySQL 和 SQLite 中不支持——得用COUNT(DISTINCT CONCAT(col1, '|', col2))曲线救国(需确保分隔符不出现在数据中) -
NULL值在COUNT(DISTINCT)中被忽略,这和普通COUNT()一致 - 大数据量下
COUNT(DISTINCT)性能较差,部分数据库(如 ClickHouse)提供近似函数uniq()加速
需要先去重再聚合?考虑子查询或 CTE
当业务逻辑明确要求“先按某些条件筛出唯一记录,再对这些记录做 SUM/AVG”时(比如每个用户最新一条订单的金额总和),不能依赖 GROUP BY,得拆成两步:
WITH latest_orders AS ( SELECT DISTINCT ON (user_id) * FROM orders ORDER BY user_id, created_at DESC ) SELECT SUM(amount) FROM latest_orders;
这个例子用了 PostgreSQL 的 DISTINCT ON;MySQL 需用窗口函数或关联子查询模拟:
SELECT SUM(t1.amount) FROM orders t1 WHERE t1.id = ( SELECT id FROM orders t2 WHERE t2.user_id = t1.user_id ORDER BY t2.created_at DESC LIMIT 1 );
这类写法性能敏感,务必给 user_id 和 created_at 加联合索引。
最常被忽略的一点:所谓“DISTINCT + 聚合”,90% 的场景其实只需要 GROUP BY;硬套 DISTINCT 关键字反而让逻辑变模糊,还容易触发兼容性问题。











