DISTINCT未去重的根本原因是作用于整行而非单字段,只要其他列值不同整行即视为不同;解决方法是只查需去重字段或改用GROUP BY配合聚合函数。

SELECT DISTINCT 为什么没去重?
常见现象是写了 SELECT DISTINCT name,结果还是看到重复的 name 值。根本原因是:DISTINCT 作用于整行,不是单个字段。只要其他列(比如 id、created_at)不同,整行就视为不同,哪怕 name 相同也会被保留。
解决办法只有两个方向:
- 明确只查需要去重的字段,且不带其他可能变化的列(如
SELECT DISTINCT name FROM user) - 若必须带其他字段,改用
GROUP BY name配合聚合函数(如MAX(id)),再做后续处理 - 注意 MySQL 5.7+ 默认开启
ONLY_FULL_GROUP_BY,直接SELECT name, id FROM user GROUP BY name会报错,需显式指定聚合逻辑
PHP 中执行 DISTINCT 查询的典型写法
和普通查询无本质区别,重点在 SQL 本身是否写对。PDO 示例:
$stmt = $pdo->prepare("SELECT DISTINCT category FROM products WHERE status = ?");
$stmt->execute([1]);
$categories = $stmt->fetchAll(PDO::FETCH_COLUMN);
关键点:
立即学习“PHP免费学习笔记(深入)”;
-
PDO::FETCH_COLUMN直接取第一列,省去嵌套数组,适合单字段去重结果 - 别用
fetch()循环取 ——fetchAll()更安全,避免漏掉最后一行 - 如果字段含空格或特殊字符,记得用反引号包裹:
SELECT DISTINCT `user name`
DISTINCT 和 GROUP BY 在性能与语义上的实际差异
两者都能实现“按某字段取唯一值”,但行为和适用场景不同:
-
DISTINCT是纯结果去重,不支持对每组做计算;GROUP BY天然支持COUNT()、AVG()等聚合,语义更明确 - 在有索引的情况下,
DISTINCT可能比GROUP BY略快(尤其只查一列时),但差别通常可忽略 - MySQL 8.0+ 对
DISTINCT做了优化,但如果去重字段没有索引,全表扫描 + 临时表排序仍不可避免 - 不要为了“看起来简洁”硬用
DISTINCT替代GROUP BY—— 比如要查“每个分类最新一条商品”,必须用GROUP BY+MAX(created_at)或窗口函数
容易被忽略的 NULL 和大小写问题
DISTINCT 把所有 NULL 视为相同值,这点没问题;但大小写敏感性取决于字段的 collation:
- 若字段是
utf8mb4_0900_as_cs(区分大小写),则'Apple'和'apple'被视为不同,都会保留 - 若想强制不区分,得在 SELECT 中统一转换:
SELECT DISTINCT LOWER(name) FROM user - 注意
LOWER()后字段别名不能用于 ORDER BY 或 WHERE —— MySQL 不允许在这些子句中直接引用别名,得重写表达式 - 如果业务上“张三”和“张 三”(含空格)算重复,
DISTINCT无法自动识别,得靠应用层清洗或加生成列索引











