mysql中distinct和group by是否忽略大小写取决于字段排序规则,可在查询中用collate临时指定;postgresql需用lower()配合子查询保留原始值;sql server可用collate database_default;跨数据库推荐group by lower(name)配合聚合函数选代表值。

MySQL 中用 COLLATE 强制统一排序规则
默认情况下,DISTINCT 和 GROUP BY 是否忽略大小写,取决于字段的 collation(排序规则)。比如 utf8mb4_0900_as_cs 是区分大小写的,而 utf8mb4_0900_as_ci 就是不区分的(_ci = case-insensitive)。直接改表结构风险大,更稳妥的做法是在查询时临时指定:
SELECT DISTINCT name COLLATE utf8mb4_0900_as_ci FROM users;- 如果字段本身是
utf8mb4_bin这类严格二进制排序,不加COLLATE就一定会把"Alice"和"alice"当作两行 - 注意:
COLLATE必须放在字段名后、AS前,不能写成SELECT DISTINCT COLLATE ...
PostgreSQL 里用 LOWER() 或 ILIKE 配合去重
PostgreSQL 默认区分大小写,且不支持 COLLATE 在 DISTINCT 中直接修饰字段。常用做法是先转小写再聚合:
-
SELECT DISTINCT LOWER(name) FROM users;—— 但只返回小写结果,丢失原始大小写格式 - 想保留原始值、仅按小写逻辑去重?得套一层子查询:
SELECT * FROM users WHERE id IN (SELECT MIN(id) FROM users GROUP BY LOWER(name)); - 别用
ILIKE替代,它只是匹配操作符,不能用于去重逻辑
SQL Server 的 COLLATE DATABASE_DEFAULT 简化写法
SQL Server 对大小写敏感性更“隐形”——可能由数据库级或列级 collation 决定。最通用的兼容写法是:
-
SELECT DISTINCT name COLLATE DATABASE_DEFAULT FROM users;—— 自动继承当前数据库默认规则(通常是不区分大小写的) - 如果报错 “Cannot resolve collation conflict”,说明参与比较的字段 collation 不一致,必须显式统一,例如:
name COLLATE SQL_Latin1_General_CP1_CI_AS -
CI_AS表示 Case-Insensitive + Accent-Sensitive,是常见生产环境选择
跨数据库可移植方案:用 LOWER() + GROUP BY 保原始字段
如果需要在 MySQL/PostgreSQL/SQL Server 上都稳定运行,又必须保留原始大小写显示,就放弃 DISTINCT,改用 GROUP BY 配合聚合函数选代表值:
-
SELECT MIN(id) AS id, name FROM users GROUP BY LOWER(name);—— 错误!name不在GROUP BY中,MySQL 5.7+ 会报错 - 正确写法:
SELECT MIN(id) AS id, MAX(name) AS name FROM users GROUP BY LOWER(name); - 更安全的组合:
SELECT * FROM users u1 WHERE NOT EXISTS (SELECT 1 FROM users u2 WHERE LOWER(u2.name) = LOWER(u1.name) AND u2.id —— 保留每组中 <code>id最小的那条原始记录
真正麻烦的不是语法,而是你无法靠一条 DISTINCT 同时满足“按小写去重”和“返回原始大小写”。必须明确:要的是结果可读性,还是业务语义一致性?后者往往要求先定义哪条算“主记录”,再用窗口函数或自连接锚定——这点常被跳过,直到线上数据对不上。










