中文排序乱码主因是校对规则(collate)不匹配,而非字符集错误;需统一使用支持中文语义的collation如utf8mb4_unicode_ci或chinese_prc_ci_as,并在字段定义、查询、join及视图中显式指定,避免依赖默认值。

中文排序乱码不是字符集错了,而是校对规则(COLLATE)没对上——哪怕字段是 NVARCHAR 或 utf8mb4,只要排序时用的 COLLATE 不支持中文语义,结果就可能“张三”排在“李四”后面、“北京”跑最后。
MySQL 中 GROUP BY / ORDER BY 中文排序错乱
现象:单条查中文正常,一加 ORDER BY name 就顺序乱,比如「王五」排到「阿明」前面;GROUP BY dept_name 后聚合值对应错位。
- 根本原因是
collation_connection默认是utf8mb4_general_ci或utf8mb4_0900_as_cs,它们按字节序或 Unicode 码点排,不按拼音/笔画 - 临时修复:查询时显式指定校对规则,例如
ORDER BY name COLLATE utf8mb4_unicode_ci(支持拼音近似)、或更准的utf8mb4_pinyin_ci(需 MySQL 8.0+ + pinyin 插件) - 建表时就该定死:字段定义带
COLLATE utf8mb4_unicode_ci,避免依赖连接层默认值 - 注意:
utf8mb4_unicode_ci对简体中文排序基本可用,但「重庆」和「重慶」会被视为不同;如需严格简繁映射,得用utf8mb4_zh_0900_as_cs(MySQL 8.0.30+)
SQL Server 中 ORDER BY 中文变成问号或顺序颠倒
现象:SELECT 出来字段显示正常,但加 ORDER BY name 后部分中文变 ?,或者「赵六」排在「陈七」之前。
- 不是字段类型问题——
NVARCHAR字段本身能存中文,但排序行为由列级COLLATE控制 - 查当前列的校对规则:
SELECT name, collation_name FROM sys.columns WHERE object_id = OBJECT_ID('your_table') AND name = 'name' - 如果返回的是
SQL_Latin1_General_CP1_CI_AS,它根本不认识中文排序逻辑,必须改:ALTER TABLE your_table ALTER COLUMN name NVARCHAR(50) COLLATE Chinese_PRC_CI_AS - 动态 SQL 更危险:拼接
ORDER BY子句时,若变量没声明为NVARCHAR或漏了N'xxx'前缀,整个排序上下文会退化成 Latin1
PostgreSQL 中中文排序不按拼音
现象:执行 SELECT * FROM user ORDER BY name;,结果是「张」「中」「啊」「北」混排,明显不是拼音顺序。
- PostgreSQL 默认用
C或POSIX校对规则,纯按字节码排序,对 UTF-8 中文完全无效 - 必须在查询中显式指定区域校对:
ORDER BY name COLLATE "zh_CN.utf8"(系统需已安装该 locale) - 验证 locale 是否可用:
SELECT * FROM pg_collation WHERE collname = 'zh_CN.utf8';;不可用则需在 OS 层运行locale-gen zh_CN.UTF-8并重启 PostgreSQL - 建表时不推荐直接设列级
COLLATE,因为 PostgreSQL 的列级校对只影响=和LIKE,不影响ORDER BY—— 所以排序逻辑必须写在查询里
跨库 JOIN 或视图中排序失效的隐藏陷阱
现象:单独查 A 表中文排序正常,B 表也正常,但 SELECT * FROM view_ab ORDER BY name 就乱;或者 A JOIN B ON a.name = b.name 匹配失败。
- JOIN 条件和排序都受两边字段的
COLLATE影响,只要一个字段是utf8mb4_general_ci、另一个是utf8mb4_unicode_ci,比较就可能静默失败 - 视图定义里不会继承外部查询的
COLLATE,必须在视图 SQL 内部显式写COLLATE,例如:SELECT name COLLATE utf8mb4_unicode_ci AS name FROM t - MySQL 视图中用
CONCAT()拼接字段时,若输入字段COLLATE不同,结果自动降级为较弱规则(如utf8mb4_0900_as_cs+utf8mb4_general_ci→ 结果用general_ci),后续排序就不可控
真正容易被忽略的是:校对规则不是“设一次就全局生效”的配置,它绑定在字段定义、连接会话、甚至单个字符串字面量上。同一张表里,name 列用 Chinese_PRC_CI_AS,remark 列却是 SQL_Latin1_General_CP1_CI_AS,那连 ORDER BY remark 都可能崩——这种混合状态在线上老库中极其常见,光看表结构不查具体列的 collation_name,永远定位不到根因。











