min()/max()对字符串返回“错”的最大值并非函数错误,而是严格按字段collation校对规则执行字典序比较,如'10'

MIN()/MAX() 对字符串返回“错”的最大值?不是函数错了,是它真正在按校对规则比较 —— 比如 '10' 会排在 '2' 前面,因为首字符 '1' 的码点比 '2' 小。
MySQL 中 MIN()/MAX() 字符串比较依赖 COLLATION
字符串字段的 MIN() 和 MAX() 结果,完全由该列的 COLLATION 决定。不是按数值大小,也不是简单 ASCII,而是按校对规则定义的“字典序”逻辑:大小写是否敏感、重音是否忽略、汉字按拼音还是笔画、空格是否参与排序……全看它。
-
utf8mb4_0900_as_cs:区分大小写 + 区分重音 + Unicode 9.0 规则,中文按拼音排序较合理 -
utf8mb4_bin:逐字节比较,'A'和'a'严格不同,'张'和'李'按 Unicode 码点排(非拼音) -
utf8mb4_general_ci:已弃用,排序不稳定,尤其对中文支持差
执行 SHOW CREATE TABLE your_table; 查看字段实际 COLLATE;若没显式指定,会继承表或数据库默认值。
如何快速验证当前排序行为是否异常
别猜,直接看原始排序顺序和字节:
- 运行
SELECT name, HEX(name) FROM t_book ORDER BY name LIMIT 5;—— 对比结果是否符合你预期的“字典序” - 如果
'10'排在'2'前面,且字段本意是数字字符串,那问题大概率不在 COLLATION,而在数据类型设计 - 临时强制指定校对验证效果:
SELECT MAX(name COLLATE utf8mb4_0900_as_cs) FROM t_book;
数字型字符串别靠 COLLATE 修,要转数值
字段存的是 '1'、'10'、'2' 这类纯数字字符串?COLLATE 再怎么调也解决不了字典序本质。必须做类型转换:
- 安全推荐:
MAX(CAST(NULLIF(TRIM(name), '') AS UNSIGNED))—— 先去空、再判空、再转无符号整数 - 避免
name + 0:遇到'年2024'会得0,'2024年'得2024,行为不可控 - 注意
CAST(... AS UNSIGNED)遇到非法内容(如'abc')会截断或报错,需提前清洗:SELECT name FROM t_book WHERE name REGEXP '^[^0-9]';
真正容易被忽略的是:校对规则不是“开关”,而是隐式参与所有字符串比较
它不只影响 ORDER BY 和 MIN()/MAX(),还影响 =、LIKE、GROUP BY、甚至 JOIN ON 条件中的字符串匹配。改一个字段的 COLLATE,可能让已有查询逻辑悄然变化 —— 尤其当多表 JOIN 或子查询混用不同校对规则时,MySQL 会按优先级隐式转换,还可能报 Illegal mix of collations 错误。










