MySQL 8.0.32中含民族字符的字符串常量比较异常问题
问题场景
在MySQL 8.0.32中搭建了如下测试环境:
CREATE SCHEMA `test_schema` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_pl_0900_ai_ci ; CREATE TABLE `test_schema`.`test_table` ( `test_column` VARCHAR(64) NULL ); INSERT INTO `test_schema`.`test_table` (`test_column`) VALUES('Łucja'); INSERT INTO `test_schema`.`test_table` (`test_column`) VALUES('Lucjan');
表和列未指定排序规则,继承了Schema的波兰语排序规则utf8mb4_pl_0900_ai_ci。执行SELECT * FROM test_table WHERE test_column LIKE 'Ł%';时,能正确返回仅包含Łucja的结果——该排序规则中Ł和L是独立字符,匹配逻辑符合预期。
但执行SELECT * FROM test_table WHERE 'Lucjan' LIKE 'Ł%';却返回两行数据,不符合预期。进一步测试发现:独立字符串(非表字段)的比较不会自动使用Schema的排序规则,比如SELECT 1 WHERE 'L' LIKE 'Ł%'会返回结果,说明此时用的不是波兰语排序规则。
现有方案的问题
- 使用
BINARY关键字可以修正问题,但在存储函数中会收到弃用警告:1287 'BINARY expr' is deprecated and will be removed in a future release. Please use CAST instead - 使用
CAST('L' AS CHAR(6) CHARSET latin2) LIKE 'Ł%'能得到正确结果,但写法繁琐。
可行解决方案
1. 会话/全局级别统一排序规则
通过设置collation_connection参数,让当前会话所有字符串比较都使用指定的排序规则:
-- 会话级别生效 SET collation_connection = 'utf8mb4_pl_0900_ai_ci';
设置后,独立字符串的LIKE比较会遵循波兰语排序规则,SELECT 1 WHERE 'L' LIKE 'Ł%'将不再返回结果,SELECT * FROM test_table WHERE 'Lucjan' LIKE 'Ł%';也只会返回正确的行。
如果需要全局永久生效,可在MySQL配置文件(如my.cnf/my.ini)中添加:
[mysqld] collation_connection = utf8mb4_pl_0900_ai_ci
注意:该设置会影响所有会话的字符串比较行为,需确认业务全场景适配该排序规则。
2. 简化CAST指定排序规则
无需指定字符集长度,直接对字符串或匹配模式指定排序规则即可,写法更简洁:
-- 对目标字符串指定排序规则 SELECT * FROM test_table WHERE CAST('Lucjan' AS CHAR) COLLATE utf8mb4_pl_0900_ai_ci LIKE 'Ł%'; -- 或对匹配模式指定排序规则 SELECT * FROM test_table WHERE 'Lucjan' LIKE 'Ł%' COLLATE utf8mb4_pl_0900_ai_ci;
这种方式仅针对单个SQL生效,适合局部需要特殊排序规则的场景。
3. 将字符串转为表字段形式
把独立字符串包装成子查询字段,让它继承当前Schema的排序规则:
SELECT * FROM test_table, (SELECT 'Lucjan' AS str) t WHERE t.str LIKE 'Ł%';
子查询的str字段会自动继承Schema的排序规则,因此比较逻辑会符合预期。
原因说明
MySQL中,表字段会继承Schema/表的排序规则,但字面量字符串的排序规则由collation_connection参数决定。默认情况下该参数可能与Schema排序规则不一致,导致独立字符串比较时使用了错误的规则,从而出现不符合预期的匹配结果。
内容的提问来源于stack exchange,提问作者Kuba D

