left()分组最简单但仅适用于ascii字符开头字段;中文需预计算拼音首字母列或引入文本处理服务,硬用sql实时计算既慢又不准。

直接用 LEFT() 分组最简单,但只适用于 ASCII 字符开头的字段
如果字段值是英文、数字或常见符号开头(比如 x001、p005),LEFT(col, 1) 就是最快最稳的方式。它不依赖排序规则、不涉及编码转换,纯字符串截取。
常见错误现象:LEFT(name, 1) 对中文返回“张”“李”“王”,结果就是按汉字本身分组,不是拼音首字母——这在业务上通常没意义。
- 适用场景:用户名、编号、SKU、邮箱前缀等明确以 ASCII 字符开头的字段
- 写法示例:
SELECT LEFT(username, 1) AS first_char, COUNT(*) FROM users GROUP BY LEFT(username, 1) - 注意:
LEFT()在 MySQL、PostgreSQL、SQL Server 都支持;SQLite 用SUBSTR(col, 1, 1) - 性能友好:只要
col有索引,LEFT(col, 1)在部分数据库(如 MySQL 8.0+)可走函数索引
中文字段想按拼音首字母分组?别碰 CONVERT(),它根本不管拼音
CONVERT(name USING gbk) 或类似写法,在 MySQL 里只会把字符转成 GBK 编码字节,再取第一个字节——得到的是区位码高位(如 0xD5),和“张”“赵”“周”的拼音 Z 完全无关。这不是 bug,是设计如此。
真正影响汉字比较顺序的是 collation,不是 CONVERT。但 collation 只控制 ORDER BY 和 = 判断,不能直接提取拼音首字母。
- MySQL 8.0+ 推荐路径:加一个预计算列
pinyin_first CHAR(1),应用层或 ETL 写入,再建索引 - SQL Server 可用
LEFT(name COLLATE Chinese_PRC_CS_AS_KS_WS, 1)配合自定义函数(如fn_pinyin),但需启用 CLR,生产环境常被禁用 - PostgreSQL 没
CONVERT函数,硬套会报错function convert does not exist;应改用unaccent()+upper(left(...)),仅对简体常用字有效(约 80%)
SUBSTRING() 和 LEFT() 本质一样,但跨数据库兼容性略差
SUBSTRING(col, 1, 1) 和 LEFT(col, 1) 功能完全等价,都是取首字符。区别在于语法习惯和数据库支持粒度:
- MySQL / SQL Server / PostgreSQL:两者都支持,
LEFT()更直白 - SQLite:只认
SUBSTR(col, 1, 1)(注意是SUBSTR,不是SUBSTRING) - Oracle:用
SUBSTR(col, 1, 1),LEFT()不支持 - 参数差异:
SUBSTRING()第二个参数是起始位置(从 1 开始),第三个是长度;LEFT()只要长度,更少出错
分组后统计时,WHERE 和 HAVING 别混用
想查“首字母为 A 的用户数”,必须用 WHERE LEFT(name, 1) = 'A';如果写成 HAVING LEFT(name, 1) = 'A',会先分完所有首字母组再过滤,效率低且逻辑错乱。
-
WHERE是分组前筛行:可用于原始字段、函数表达式(如LEFT()),但不能用聚合函数 -
HAVING是分组后筛组:只能用于分组字段或聚合结果(如COUNT(*) > 10) - 空值陷阱:
LEFT(NULL, 1)返回NULL,会被单独分进一组;若不想统计,加WHERE name IS NOT NULL - 大小写敏感:默认区分大小写,
'A'和'a'是两组;需要合并可用UPPER(LEFT(name, 1))










