CONVERT不能正确提取中文拼音首字母,因GBK编码与拼音无关,真正起作用的是排序规则(collation);应使用支持拼音排序的collation(如MySQL 8.0+的utf8mb4_0900_as_cs)、SQL Server的Chinese_PRC_CS_AS_KS_WS,或PostgreSQL的unaccent扩展,最佳实践是应用层预计算pinyin_first字段。

MySQL里用CONVERT转拼音首字母分组会失败
直接对中文字段用CONVERT(col USING gbk)再取首字符,大概率分不出正确拼音首字母——GBK编码下“张”“赵”“周”首字都是0xD5这类区位码值,和拼音无关。
真正起作用的是排序规则(collation)隐式转换,不是CONVERT本身。常见错误现象:SELECT LEFT(CONVERT(name USING gbk), 1) 返回乱码或全一样;或者分组结果把“李”“刘”“林”全归进同一组。
- 必须用支持拼音排序的collation,比如
utf8mb4_unicode_ci不行,它按Unicode码点排,“阿”(U+963F)和“八”(U+516B)首字母根本不对齐 - MySQL 8.0+ 推荐用
utf8mb4_0900_as_cs(大小写敏感+重音敏感),配合ORDER BY能近似按拼音序,但GROUP BY仍不能直接提取首字母 - 稳妥做法是加个映射表或生成拼音首字母列,别硬靠
CONVERT“猜”
SQL Server中COLLATE才是拼音分组的关键
SQL Server 的Chinese_PRC_CS_AS_KS_WS这类collation才真正支持汉字按拼音排序,CONVERT在这里只是辅助类型转换,不是核心。
典型误用:CONVERT(VARCHAR, name) COLLATE Chinese_PRC_CI_AS —— CI_AS不区分大小写也不区分重音,拼音排序不准;且没指定长度,可能截断。
- 分组前先用
LEFT(name COLLATE Chinese_PRC_CS_AS_KS_WS, 1)取首字,再配合UNICODE()或自定义函数转拼音首字母 - 更可靠的是用
fn_pinyin等扩展函数(需启用CLR),或提前在应用层/ETL中计算好pinyin_first列并建索引 - 注意:
COLLATE只影响比较和排序行为,不影响存储编码;CONVERT若用于改变编码(如UTF8→GBK),反而可能引入?号丢失
PostgreSQL用unaccent扩展 + upper()模拟拼音首字母
PostgreSQL 没原生拼音支持,CONVERT也不是它的函数(那是MySQL/SQL Server的),常见错误是搜到过时教程,硬套CONVERT(... USING ...)语法,直接报function convert does not exist。
真实路径是:先去音调、转大写、再取首字符,对简体中文勉强可用(覆盖约80%常用字)。
- 确保已启用
unaccent扩展:CREATE EXTENSION IF NOT EXISTS unaccent; - 分组写法:
SELECT upper(left(unaccent('zh-CN'::regconfig, name), 1)) AS first_letter, count(*) FROM users GROUP BY first_letter; - 注意:
unaccent对多音字(如“重庆”的“重”)、生僻字、繁体字无效;zh-CNregconfig 并非所有版本都预置,可能要手动加载词典 - 性能上,
unaccent()无法走索引,大数据量务必加函数索引:CREATE INDEX idx_name_pinyin ON users (upper(left(unaccent('zh-CN', name), 1)));
跨数据库统一方案:别依赖CONVERT,用应用层预计算
所有试图用CONVERT或COLLATE纯SQL搞定拼音首字母分组的方案,最终都会卡在多音字、异体字、新造词或性能上。
实际项目里最省心的做法,是在写入时就存一个pinyin_first字段(如“王”→W,“褚”→CHU→取C),而不是每次查都算。
- 用Python的
pypinyin、Java的pinyin4j、Node.js的pinyin库生成首字母,比SQL函数稳定得多 - 避免在SQL里调用UDF做拼音转换——MySQL UDF难维护,SQL Server CLR权限麻烦,PG的PL/Python又受限于服务器环境
- 如果必须SQL内解决,优先考虑MySQL 8.0+的
JSON_TABLE+ 预置拼音映射表,而非CONVERT硬转
拼音首字母看着简单,但每个数据库的字符集、collation、扩展能力差异太大,硬靠CONVERT兜底,迟早掉进排序规则失效、多音字错分、查询慢三连坑里。

















