MySQL 中 SUBSTRING 截取中文乱码?本质是字节 vs 字符混淆 开门见山,先说核心结论:SUBSTRING 函数默认是按字节来截取的。问题就出在这里——在 utf8mb4 编码下,一个中文字符可能占用 3 到 4 个字节。如果你用 SUBSTRING 配合 LENGTH() 函数(它返
开门见山,先说核心结论:SUBSTRING 函数默认是按字节来截取的。问题就出在这里——在 utf8mb4 编码下,一个中文字符可能占用 3 到 4 个字节。如果你用 SUBSTRING 配合 LENGTH() 函数(它返回的是字节数)去操作,结果必然是“丢三落四”,截到半个汉字,乱码也就随之而来。那么正确的搭档是谁呢?是 CHARACTER_LENGTH()。这个函数返回的是我们肉眼可见的字符数,用它来配合 SUBSTRING,才能精准地定位到“第几个字”。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
首先要澄清一个常见的误解:SUBSTRING 函数本身并不区分编码,它的参数 pos(起始位置)和 len(长度)在定义上就是基于“字符数”来计算的。但这里有个关键前提:你传给它的这两个数值,本身就必须是字符数,而不能是字节数。
SUBSTRING(name, LENGTH(LEFT(name, 2)), 1)。这行代码试图先取前2个字节,再用 LENGTH() 计算其字节长度作为起始位。问题在于,LEFT(name, 2) 取出的2个字节很可能只是一个汉字的一部分,导致后续计算完全失控。SUBSTRING(name, 1, 2) 就是取前2个字符,简单明了。如果需要动态计算,比如取最后2个字符,可以写成:SUBSTRING(name, CHARACTER_LENGTH(name) - 2 + 1, 2)。utf8mb4 的排序规则(例如 utf8mb4_0900_as_cs)下,SUBSTRING 的行为是稳定可靠的。但如果使用的是老旧的 utf8(实际上是 utf8mb3),遇到一些四字节的 Emoji 表情时,仍然可能出现问题。是不是用了 CHARACTER_LENGTH() 就高枕无忧了?并非如此。这个函数返回的是 Unicode 字符的个数,但它依赖于字段本身声明的字符集。想象一下这个场景:一个字段被定义成了 latin1 字符集,但实际存储的却是 UTF-8 编码的中文。这时,CHARACTER_LENGTH() 可能会把一个汉字错误地计算为3个字符。这可不是函数的bug,而是数据存储层出现了编码错配。
SHOW FULL COLUMNS FROM table_name LIKE 'column_name';,重点关注 Collation 列,确保它指向的是 utf8mb4_* 系列的排序规则。SUBSTRING(CONVERT(column_name USING utf8mb4), 1, 5)。不过,这种方法有性能开销,不建议在数据量大的表或 WHERE 条件中频繁使用。LEFT(column_name, 5) 和 SUBSTRING(column_name, 1, 5) 的效果是完全一样的,前者写起来更简洁。RIGHT() 函数同理。有时候,明明 SQL 语句写得滴水不漏,可执行结果还是乱码,甚至返回空字符串或问号。这时候,问题很可能出在数据库连接层。如果客户端连接使用的是 latin1 编码,或者没有正确设置 SET NAMES utf8mb4,那么 SUBSTRING 函数接收到的就已经是一个被损坏的字符串了,后续无论怎么计算字符数都是徒劳。
mysql --default-character-set=utf8mb4 -u user -p。SELECT @@character_set_client, @@character_set_connection, @@character_set_results;,确保这三个系统变量的值都是 utf8mb4。SUBSTRING('你好世界', 1, 2) 却返回了空值或乱码。这大概率是客户端解码失败导致的,并非函数本身失效。说到底,真正让人头疼的往往不是函数语法怎么写,而是字符集声明、连接参数、实际字段存储这三者是否保持了一致。只要其中任何一层没有对齐,少了一个关键的 mb4CHARACTER_LENGTH() 都可能功亏一篑。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述