SQL Server 中使用 COLLATE Chinese_PRC_CI_AS 可实现原生拼音排序,最简方式是建表或修改列时直接指定该排序规则;临时排序可用 ORDER BY 字段名 COLLATE Chinese_PRC_CI_AS,但高频查询应避免重复书写。

SQL Server 中用 COLLATE Chinese_PRC_CI_AS 直接排序最省事
SQL Server 原生支持拼音排序,关键不是写函数,而是列的排序规则(collation)。只要字段是 nvarchar 类型,且查询时指定 Chinese_PRC_CI_AS,ORDER BY 就会按拼音顺序排——包括首字母分组效果。
常见错误是:字段本身用的是 SQL_Latin1_General_CP1_CI_AS,却在 ORDER BY 里硬加 COLLATE,结果部分汉字仍乱序。正确做法是:
- 建表或修改列时直接设 collation:
ALTER TABLE 表名 ALTER COLUMN 字段名 nvarchar(50) COLLATE Chinese_PRC_CI_AS - 临时生效可加后缀:
ORDER BY 字段名 COLLATE Chinese_PRC_CI_AS,但每次都要写,不推荐用于高频查询 - 注意大小写不敏感(
CI),若需区分大小写请用CS版本
MySQL 5.7 及更早版本不能靠 CONVERT(... USING gbk) 实现拼音首字母
很多人试过 ORDER BY CONVERT(name USING gbk),发现排序还是不对——因为 CONVERT 只改字节编码,不改变排序逻辑;真正起作用的是 collation。而 gbk_chinese_ci 实际按部首笔画排,utf8mb4_unicode_ci 按 Unicode 码位排,两者都不等于拼音顺序。
更麻烦的是:含 emoji、生僻字或超长 UTF-8 字符时,CONVERT(... USING gbk) 可能截断或转成问号,导致数据错乱。
所以这条路本质走不通。如果必须用 MySQL 5.7,只能选下面两种之一:
- 建一张 23 行的映射表(如
t_py_first),存每个首字母对应汉字区间('吖'→'八'、'八'→'嚓'…),然后用BETWEEN或子查询匹配 - 用自定义函数(如
f_GetPy)逐字查表映射,但性能差——尤其对大表WHERE f_GetPy(name) = 'S'几乎无法走索引
自定义函数提取首字母时,unicode() 区间判断比查表快但覆盖不全
有些函数用 unicode(@word) between 19968 and 40869 判断是否为汉字,再查预置数组返回首字母。这种方式免去 JOIN 映射表,执行快,但问题明显:
- Unicode 中文区(U+4E00–U+9FFF)只覆盖常用字,缺冷僻字、扩展 A/B 区(如「?」「?」)、繁体异体字
- 同一个拼音首字母对应多个 Unicode 区段(比如「q」字既在基本区,也在扩展 B 区),硬编码容易漏判
- 函数内用
WHILE循环 +SUBSTRING处理多字字符串,N 字符串就要 N 次循环,大数据量下 CPU 吃紧
实操建议:仅用于中小表、低频查询;生产环境高并发场景,宁愿提前算好首字母存在冗余字段里,用 INDEX 加速。
真正稳定的方案:把首字母存成计算列或触发器维护
别让每次查询都现场算拼音——这是所有“函数方案”慢的根本原因。SQL Server 支持持久化计算列,MySQL 可用触发器或应用层写入,把首字母固化下来:
- SQL Server 示例:
ALTER TABLE 用户表 ADD py_first AS LEFT(dbo.f_GetPy(姓名), 1) PERSISTED,再给该列建索引 - MySQL 示例:在
INSERT/UPDATE时用应用代码或存储过程生成py_first字段值,而非依赖运行时函数 - 注意:中文字段内容变更时,这个首字母字段必须同步更新,否则查出来就是错的
复杂点在于维护一致性——但比起每次查询都跑一遍低效函数,这点额外工作换来的是稳定响应和可预测性能。

















