1. CONVERT函数的两种形态:从SQL标准到ODBC风格的差异
我最早接触CONVERT是在接手一个老项目的时候。那个项目的数据库里存了一堆“看起来是数字其实是字符串”的字段,订单金额、用户积分、商品销量,全是varchar。当时有个报表要按金额排序,结果排序结果惨不忍睹:900排在了9999后面,因为字典序和数值序根本不是一回事。我一查,发现大家连类型转换都没做,直接ORDER BY,MySQL就只能按照字符串的字符顺序去排。
要解决这类问题,首先得搞清楚MySQL里CONVERT到底有多少种写法。很多刚入行的同学以为CONVERT就是一个固定写法,其实它有两套风格,长得不一样,用的场景也不一样。
1.1 ANSI/标准语法:CONVERT(expr, type)
这是最常用的一种,表达很直白:把表达式expr转换成type指定的数据类型。语法长这样:
sql复制CONVERT(expr, type)
type支持的类型有这些:
| 类型 | 说明 | 示例 |
|---|---|---|
| BINARY | 转成二进制字符串 | CONVERT('abc', BINARY) |
| CHAR | 转成字符串,可带字符集参数 | CONVERT('abc', CHAR(10)) |
| DATE | 转成日期 | CONVERT('2024-05-01', DATE) |
| DATETIME | 转成日期时间 | CONVERT('2024-05-01 12:30:00', DATETIME) |
| DECIMAL | 转成定点小数 | CONVERT('123.45', DECIMAL(10,2)) |
| SIGNED | 转成有符号整数 | CONVERT('-100', SIGNED) |
| UNSIGNED | 转成无符号整数 | CONVERT('100', UNSIGNED) |
| TIME | 转成时间 | CONVERT('12:30:00', TIME) |
| YEAR | 转成年份(MySQL 8.0.22+) | CONVERT('2024', YEAR) |
注意,这里有个到处都会踩的小坑:SIGNED是有符号,UNSIGNED是无符号。如果字符串里存的是负数,你用UNSIGNED去转,结果会溢出。比如CONVERT('-1', UNSIGNED),在MySQL里会返回一个很大的数(18446744073709551615),因为无符号整数没有负数概念,负数会绕到最大值那边去。这个坑我在线上环境见过不止一次,后面详细讲。
1.2 ODBC风格语法:CONVERT(expr USING transcoding_name)
这是第二种写法,专门用于字符集转换,语法完全不一样:
sql复制CONVERT(expr USING transcoding_name)
USING后面跟的是字符集名称,比如utf8mb4、gbk、latin1。这个语法的作用是把字符串从当前字符集转成目标字符集。举例,如果你有一个gbk编码的字段,要转成utf8mb4,可以这样:
sql复制SELECT CONVERT(username USING utf8mb4) FROM user_info;
但要小心,别把这两种语法混在一起。我之前见过有人写CONVERT('abc', USING utf8mb4),也见过CONVERT('abc', CHAR USING utf8mb4),都报语法错误。正确写法只有两种,要么CONVERT(expr, CHAR),要么CONVERT(expr USING charset),中间别混着来。
MySQL官方文档里还有第三种写法,带USING和逗号参数组合的完整形式,但实际开发中极少用到,我也几乎没有在生产环境见过,知道有这回事就行。
1.3 和CAST函数的关系:同一个世界的两个名字
说到CONVERT,就绕不开CAST。MySQL里CAST也是做类型转换的,语法:CAST(expr AS type)。很多人分不清它俩到底有什么区别,其实在MySQL里,它俩在绝大多数场景下是等价的。
| 对比项 | CONVERT | CAST |
|---|---|---|
| 语法 | CONVERT(expr, type) | CAST(expr AS type) |
| 字符集转换 | 支持CONVERT(expr USING charset) | 不支持 |
| 支持的类型 | 全部 | 全部 |
| 标准兼容性 | ODBC风格 | SQL标准 |
实际使用中,我个人的习惯是:只在字符集转换时用CONVERT,其他的类型转换统一用CAST。这个习惯来源于代码可读性——CAST(expr AS DECIMAL(10,2))一眼就能看出是标准SQL,跨数据库迁移的时候不用改。但如果你所在团队更习惯CONVERT,也没问题,只是保持一致就好。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 字符串转数字:一张订单表的varchar字段是如何逼疯我的
说回我开头提到的那个订单表。那个表的金额字段叫amount,设计表的人不知道为什么用了varchar(20)。当时面临的具体问题是:报表要给每个
