CAST 是标准写法,四家都认;CONVERT 是 SQL Server 扩展,多一个样式码参数。
隐式转换是最大的坑:SQL Server 遇到 'abc' 转 INT 会报错,SQLite 直接给 0。
日期转字符串用样式码 112(yyyymmdd)最安全,没有分隔符就不受语言设置影响。
转换函数解决的是「类型对不上」的问题。
字段是 varchar,要按数字排序;日期存成了字符串,要按日期比——这些都要转换。
教材 7.4 只有三小节:CAST、CONVERT、两种写法的差别。
节短,但第三小节是重点——它讲的是「什么时候必须用 CONVERT」。
演示里跑了五组「字符串转整数」,
看 SQLite 怎么把 'abc' 变成 0——同样的操作在 SQL Server 里会直接报错,
这是两边差别最大的一处。
一、两种写法,各管一段
| 来源 | 写法 | 谁认 |
|---|---|---|
| 标准 SQL | CAST(表达式 AS 类型) |
四家都认 |
| SQL Server | CONVERT(类型, 表达式, 样式码) |
只有它认 |
能跨库的只有 CAST。 所以「数据本身」的类型转换一律用它——转成 INT、VARCHAR、DECIMAL,
这些都不涉及格式,CAST 够了。
CONVERT 多出来的第三个参数叫「样式码」,专门控制日期字符串的格式。
这是 CAST 做不到的事——CAST(日期 AS VARCHAR) 出来的格式由服务器设置决定,你控不了。
所以分工很清楚: 数值和类型转换用 CAST,日期转成给人看的字符串用 CONVERT 加样式码。
这一条就是教材第三小节说的「两种写法的差别」。
二、隐式转换:最大的坑
「隐式转换」是指不写 CAST,数据库自己转。 比如 WHERE varchar列 = 123,
它会试着把 varchar 转成数字,或者把 123 转成字符串。
| 值 | SQLite 转 INT | SQL Server 转 INT |
|---|---|---|
'123' |
123 | 123 |
'12.5' |
12 | 报错(要转 DECIMAL) |
'abc' |
0 | 报错 |
'12abc' |
12 | 报错 |
'' |
0 | 报错 |
后三行是本质差别。 SQLite 是「能转多少算多少」,转不了就给 0;SQL Server 是「转不了就报错」。
哪种好? 从数据质量看,报错更好——它逼你在写入前把数据弄干净。
从「不想被中断」看,给 0 更顺——但那个 0 会静静躺在表里,直到有人算平均值。
所以本课的立场是:别依赖隐式转换。 该写 CAST 就写,
写清楚「我要转成什么」,比让数据库猜安全。
还有一个更隐蔽的坑:隐式转换会让索引失效。WHERE varchar列 = 123 里,
列被转成了数字——索引是按字符串建的,用不上了。
正确写法是 WHERE varchar列 = '123',让常量去转换。
三、日期样式码
| 样式码 | 格式 | 例子 |
|---|---|---|
101 |
mm/dd/yyyy |
10/31/2026 |
102 |
yy.mm.dd |
26.10.31 |
103 |
dd/mm/yyyy |
31/10/2026 |
112 |
yyyymmdd |
20261031 |
120 |
yyyy-mm-dd hh:mi:ss |
2026-10-31 14:30:00 |
126 |
ISO 8601 | 2026-10-31T14:30:00 |
112 那个 yyyymmdd 最值得记。 它没有分隔符,
不受语言设置影响——所以「把日期转成字符串发给别的系统」时,一般就用它。
126 是 ISO 8601,带 T 分隔符。 给程序解析最省事,
JavaScript、Python 的日期解析器都认这个格式。
101、103 这两种「带斜杠」的格式要少用。它们跟 '10/11/2026' 那个坑是一回事——
同一个字符串在不同地区是不同日期。
样式码只有 CONVERT 认,CAST 没有这个参数。所以「要把日期转成 20261031 这种格式」这件事,
只能用 CONVERT——这就是「什么时候必须用 CONVERT」的答案。
四、转换失败的两种处理
| 写法 | 行为 | 什么时候用 |
|---|---|---|
CAST(x AS INT) |
失败就报错 | 数据干净时 |
TRY_CAST(x AS INT) |
失败给 NULL |
数据脏、不能中断时 |
TRY_CONVERT(INT, x) |
同上 | 要样式码时 |
TRY_CAST 和 TRY_CONVERT 是 SQL Server 2012 加的。它们把「报错」变成「给 NULL」——
适合「先跑通、再清洗」的场景。
但 NULL 比 0 更隐蔽。 0 至少是个数,参与计算还能发现不对;
NULL 参与计算会传染——NULL + 1 还是 NULL,一路传到结果里。
所以推荐的做法是: 先用 TRY_CAST 找出转不了的行(WHERE TRY_CAST(...) IS NULL),
把它们清干净,再用 CAST。一步变两步,但数据是干净的。
SQLite 没有 TRY_CAST。 它的 CAST 本来就不报错,
所以不需要——这又回到那个差别:不报错不等于更安全。
五、动手 Demo:隐式转换与样式码
这一段先对比 CAST 和 CONVERT 两种写法,再跑五组「字符串转整数」看 SQLite 怎么处理脏数据,
最后列日期样式码,说明为什么 112 最安全。
import sqlite3
c = sqlite3.connect(u":memory:")
# 脏数据转整数:SQLite 是「能转多少算多少」
for v in ('123', '12.5', 'abc', '12abc', ''):
n = c.execute(u"SELECT CAST(? AS INTEGER)", (v,)).fetchone()[0]
print(repr(v), u"-> ", n)
# 日期转字符串:CAST 控不了格式
d = c.execute(u"SELECT date('2026-10-31')").fetchone()[0]
print(u"原样:", d)
print(u"去横杠:", c.execute(
u"SELECT replace(date('2026-10-31'), '-', '')").fetchone()[0])
实跑输出:
--------------------------------------------------------------------
CAST 与 CONVERT
--------------------------------------------------------------------
① 两种写法,同一个目的
--------------------------------------------------------------------
| 来源 | 写法 | 谁认 |
|---|---|---|
| 标准 SQL | CAST(表达式 AS 类型) | 四家都认 |
| SQL Server | CONVERT(类型, 表达式, 样式码) | 只有 SQL Server 认 |
CAST 是标准,CONVERT 是 SQL Server 的扩展。
CONVERT 多一个「样式码」参数,专门控制日期字符串的格式——这是 CAST 做不到的。
② 隐式转换:'abc' 转成数字是 0
--------------------------------------------------------------------
| 值 | CAST 成 INT |
|---|---|
| '123' | 123 |
| '12.5' | 12 |
| 'abc' | 0 |
| '12abc' | 12 |
| '' | 0 |
abc 和空字符串都转成了 0,12abc 转成了 12——SQLite 是「能转多少算多少」。
SQL Server 完全不同:'abc' 转 INT 直接报错「将 varchar 转换为 int 时失败」。
所以「转换失败当 0」这个行为是 SQLite 的,别拿它去推 SQL Server。
反过来说,SQL Server 报错是好事——它逼你在写入前把数据弄干净。
③ 日期格式化:样式码 101 和 112
--------------------------------------------------------------------
| 样式码 | 格式 | 例子 |
|---|---|---|
| 101 | mm/dd/yyyy | 10/31/2026 |
| 102 | yy.mm.dd | 26.10.31 |
| 103 | dd/mm/yyyy | 31/10/2026 |
| 110 | mm-dd-yyyy | 10-31-2026 |
| 112 | yyyymmdd | 20261031 |
| 120 | yyyy-mm-dd hh:mi:ss | 2026-10-31 14:30:00 |
| 126 | ISO8601 | 2026-10-31T14:30:00 |
这些样式码只有 CONVERT 认,CAST 没有这个参数。
112 那个 yyyymmdd 最值得记——它没有分隔符,不受语言设置影响,
所以「把日期转成字符串发给别的系统」时,一般就用它。
126 是 ISO 8601 格式,带 T 分隔符,给程序解析最省事。
④ 转换的三种写法对比
--------------------------------------------------------------------
| 写法 | 说明 | 可移植性 |
|---|---|---|
| CAST(x AS INT) | 标准写法 | 跨库可用 |
| CONVERT(INT, x) | SQL Server 简写 | 不跨库 |
| CONVERT(VARCHAR, d, 112) | 带样式码 | 只有它能控格式 |
能跨库的只有第一种。所以「数据本身」的转换用 CAST,「给人看的格式」用 CONVERT。
这个分法很实用:数值、类型转换不涉及格式,用 CAST 就够了;
日期转成 20261031 这种给人看的字符串,就必须用 CONVERT 加样式码。
教材 7.4 的第三小节「两种写法的差别」讲的就是这件事。
第一段五行是本节最该看的:'abc' 转成了 0,'12abc' 转成了 12。
这两行在 SQL Server 里都会报错——所以别拿 SQLite 的行为去推 SQL Server。
「能转多少算多少」看着友好,实际很危险。 那个 0 会静静躺在表里,
直到有人算平均值——然后平均分莫名其妙地低。
第二段说明 CAST 的局限:它只能换类型,控不了格式。SQLite 里没有 CONVERT,
所以要得到 20261031,只能用 replace 把横杠去掉——这是个变通写法,不是标准做法。
真实 SQL Server 里一句 CONVERT(VARCHAR, 日期, 112) 就够了。这就是「样式码」的价值——
它把格式的控制权交给你,而不是交给服务器设置。
30 秒实验
- 在你的库上跑
SELECT CAST('abc' AS INT)。 SQL Server 会报「将 varchar 转换为 int 时失败」,SQLite 给 0——两边完全不同。 - 跑
SELECT CONVERT(VARCHAR, GETDATE(), 112)和CONVERT(VARCHAR, GETDATE(), 120)。 一个得 20261031,一个得 2026-10-31 14:30:00——这就是样式码的作用。 - 想一想:为什么
WHERE varchar列 = 123会让索引失效? 因为列被隐式转成了数字,而索引是按字符串建的。 写成WHERE varchar列 = '123',让常量去转换,索引就能用。
常见误区
- 「
CAST和CONVERT差不多,随便用」。CONVERT多一个样式码, 能控日期格式——这是CAST做不到的。而且CONVERT只有 SQL Server 认,不跨库。 - 「转换失败给 0 更安全,不会中断程序」。0 会静静躺在表里,直到有人算平均值。
NULL更糟——它会一路传染。 正确做法是先把脏数据找出来清掉。 - 「
WHERE 字符串列 = 123和= '123'一样」。结果可能一样, 但后者能用索引,前者不能——因为前者把列转成了数字,索引失效。
自测三问(点开对答案)
1. 什么时候必须用 `CONVERT` 而不能用 `CAST`? —— **需要控制日期转字符串的格式时。** `CONVERT` 有样式码参数, `CAST` 出来的格式由服务器设置决定——**你控不了。** 2. `'abc'` 转 `INT`,SQLite 和 SQL Server 各给什么? —— **SQLite 给 0,SQL Server 报错。** SQLite 是「能转多少算多少」, SQL Server 是「转不了就报错」——**从数据质量看,报错更好。** 3. 为什么 `WHERE 字符串列 = 123` 会让索引失效? —— **因为它把列隐式转成了数字,而索引是按字符串建的。** **改成 `WHERE 字符串列 = '123'`,让常量去转换,索引就能用上。**下一篇 7.5 讲系统函数。 这类函数不处理数据,只回答「我在哪儿」——当前库叫什么、我是谁、从哪连过来的。 排查问题时它们比任何规范都实在。
- ☐ (本篇完,下一篇 7.5 系统函数)