MySQL 8.0.22+ 支持 COUNT(DISTINCT col1, col2) 直接统计列组合唯一值,旧版及 PostgreSQL、SQL Server 等不支持该语法;PostgreSQL 需用 COUNT(DISTINCT (col1, col2)),SQL Server 和 Oracle 必须用子查询 SELECT COUNT(*) FROM (SELECT DISTINCT col1, col2 FROM t) AS _。

MySQL 8.0.22+ 可直接用 COUNT(DISTINCT col1, col2),其他主流数据库(PostgreSQL、SQL Server、Oracle)不支持该语法,必须换写法。
MySQL 8.0.22+ 以外的版本报错:Operand should contain 1 column(s)
这是旧版 MySQL(如 5.7)或跨库迁移时最常遇到的错误。解析器把 DISTINCT 当作单值修饰符,遇到逗号就直接拒绝。
- 确认版本:
SELECT VERSION();—— 小于8.0.22就别硬写多列 - 别试图加括号绕过:
COUNT(DISTINCT (col1, col2))在 MySQL 中无效,会报语法错误 - 临时表场景下(比如在存储过程中多次引用),子查询别名不能省,否则 MySQL 报
Every derived table must have its own alias
PostgreSQL 正确写法是 COUNT(DISTINCT (col1, col2))
注意外层括号不是可选的——(col1, col2) 是行构造器(row constructor),不是字段列表。漏掉括号就会触发 syntax error at or near ","。
-
COUNT(DISTINCT col1, col2)→ 直接报错 -
COUNT(DISTINCT (col1, col2))→ 正确,NULL 值会被保留为独立组合(如(NULL, 'a')≠(NULL, 'b')) - 性能上,PostgreSQL 对整行做哈希去重,如果
(col1, col2)无索引,EXPLAIN里大概率出现HashAggregate+ 全表扫描
SQL Server 必须用子查询:SELECT COUNT(*) FROM (SELECT DISTINCT ...)
这是目前最通用、最稳妥的写法,所有版本都支持,且语义清晰。
- 子查询别名不可省:
SELECT COUNT(*) FROM (SELECT DISTINCT a, b FROM t) AS x—— SQL Server 强制要求别名,否则报Incorrect syntax near ')' - 别在子查询里多选无关列(比如
id或created_at),否则DISTINCT失效 - 大数据量时,
SELECT DISTINCT可能走Sort算子,建议提前在(col1, col2)上建联合索引
拼接字符串模拟多列 DISTINCT 极易出错
像 COUNT(DISTINCT CONCAT(col1, '|', col2)) 这类写法看似简单,但边界情况太多,线上环境慎用。
-
CONCAT(NULL, '|', 'x')结果是NULL,整行被丢弃 → 计数偏少 - 若
col1 = 'a|b'且col2 = 'c',拼成'a|b|c';而col1 = 'a'、col2 = 'b|c'也拼成同样结果 → 假合并 - MySQL 中
CONCAT()默认返回VARCHAR(1024),超长截断无声发生
真正影响结果准确性的,往往不是语法能不能跑通,而是 NULL 处理逻辑和数据内容是否可控——这点比选哪种写法更关键。

















