数字常量:1.5e3 是科学计数,0x1F 是十六进制;小数默认按 decimal 处理。
字符串一律单引号;里面含单引号就写两遍——'it''s',不是反斜杠。
日期常量本质还是字符串,只有 yyyyMMdd 和 yyyy-MM-dd 永远安全。
常量就是「写死在 SQL 里的值」。
看着最简单,但它是类型推断的源头——长度不对、精度不对、格式不对,八成是常量写错了。
教材 6.2 分四小节:数字、字符串、日期时间、符号常量。
前三节是字面量,第四节其实不是常量——@@VERSION 这类东西会变,只是写法上像常量。
演示里把五种数字写法、四种字符串写法、四种日期写法全跑了一遍,
重点看「写进去之后取出来是什么类型」——这一列最能说明问题。
一、数字常量:五种写法
| 写法 | 含义 | 算出来 | 类型 |
|---|---|---|---|
123 |
整数 | 123 | int |
-45 |
负整数 | -45 | int |
3.14 |
小数 | 3.14 | float |
1.5e3 |
科学计数 | 1500.0 | float |
0x1F |
十六进制 | 31 | int |
科学计数法的 e 不区分大小写,1.5e3 和 1.5E3 一样,都等于 1500。
这个写法在存「毫秒数」「字节数」的时候偶尔会用到,日常很少。
0x1F 这种写法在 SQL Server 里含义不同。 SQL Server 的 0x 前缀表示「二进制常量」,
不是数字——0x1F 是一个长度为 1 字节的二进制值,不是 31。这是方言差异。
小数常量的类型要注意。 标准 SQL 里 3.14 是精确小数(decimal),
不是浮点——所以 SELECT 3.14 * 2 得 6.28,不会有浮点误差。
但存进 float 列之后就变成浮点了。
二、字符串常量:单引号,双写转义
| 写法 | 说明 | 取出来 |
|---|---|---|
'hello' |
普通字符串 | hello |
'it''s' |
含单引号,写两遍 | it's |
'中文也行' |
Unicode 字符 | 中文也行 |
'<b>' |
尖括号不用转义 |
字符串一律用单引号。 双引号在标准 SQL 里是「标识符」——包着的是表名、列名,不是字符串。
SQL Server 在 QUOTED_IDENTIFIER 关闭时也把双引号当字符串,但那是历史包袱,别依赖。
含单引号的字符串,把单引号写两遍:'it''s'。 这是标准写法。
反斜杠转义 \' 只在 MySQL 里能用,SQL Server 不认——写过去会被当成两个字符。
尖括号、百分号、下划线都不用转义。 它们只在 LIKE 里有特殊含义,普通字符串里就是普通字符。
这一点跟 XML、HTML 的习惯不同,容易多此一举。
还有个坑:N'中文' 前面那个 N。 SQL Server 里它表示「这是 Unicode 字符串」,
存进 nvarchar 列时要用。不写 N 的话,某些排序规则下中文会变成问号。
三、日期常量:本质是字符串
SQL Server 没有「日期字面量」这种语法,
你写的 '2026-10-31' 就是个字符串,由它自己按格式猜成日期。 这就是为什么格式很重要。
| 写法 | 安全吗 | 原因 |
|---|---|---|
'20261031' |
永远安全 | 无分隔符,无歧义 |
'2026-10-31' |
安全 | ISO 格式,各家都认 |
'2026/10/31' |
基本安全 | 部分地区认 |
'10/11/2026' |
危险 | 月日顺序看语言设置 |
最后一行是真会出事的。 同一个 '10/11/2026',在美式设置下是 10 月 11 日,
在英式设置下是 11 月 10 日。换台服务器、换个语言,数据就错了一个月。
所以教材建议写 'yyyyMMdd'。 没有分隔符就没有歧义,也不受语言设置影响。
代价是可读性差一点——但正确比好看重要。
带时间的写法也一样。 '2026-10-31T14:30:00' 里的 T 是 ISO 8601 的分隔符,
SQL Server 2012 之后认它。在那之前得写空格。
四、符号常量:那几个 @@ 开头的
| 常量 | 是什么 | 本沙箱能跑吗 |
|---|---|---|
@@VERSION |
版本信息字符串 | 不能,T-SQL 专有 |
@@ROWCOUNT |
上条语句影响的行数 | 不能 |
@@IDENTITY |
最后插入的自增值 | 不能 |
@@ERROR |
上条语句的错误号 | 不能 |
CURRENT_TIMESTAMP |
当前时间,标准 SQL | 能 |
前四个严格说不是常量,是全局变量——它们会变。 教材归到「符号常量」里,是因为写法上像常量:
不用声明,直接用。
@@ROWCOUNT 有个陷阱:任何一条语句执行后它都会重置。 所以「查一下影响了几行,
再判断要不要回滚」这种写法,中间不能插别的语句——一插就归零了。
CURRENT_TIMESTAMP 是标准 SQL 的,四家都认。 它能当默认值用:DEFAULT CURRENT_TIMESTAMP。
GETDATE() 只有 SQL Server 认。
写跨库脚本时,CURRENT_TIMESTAMP 比 GETDATE() 值钱。这一点跟 6.1 说的是同一个原则:
能用标准的就用标准的。
五、动手 Demo:五种数字、四种字符串、四种日期
这一段把三类字面量各跑一遍,重点看「写进去之后取出来是什么类型」。
最后列那几个 @@ 开头的,并说明哪一个能真跑。
import sqlite3
c = sqlite3.connect(u":memory:")
# 数字常量:连类型一起看
for v in (u"123", u"-45", u"3.14", u"1.5e3", u"0x1F"):
got = c.execute(u"SELECT %s" % v).fetchone()[0]
print(u"%-8s -> %-8s %s" % (v, got, type(got).__name__))
# 字符串:单引号写两遍就是转义
for v in (u"'it''s'", u"'中文也行'"):
print(v, u"->", c.execute(u"SELECT %s" % v).fetchone()[0])
# 日期:本质还是字符串
for v in (u"'2026-10-31'", u"'20261031'"):
print(v, u"->", c.execute(u"SELECT %s" % v).fetchone()[0])
print(u"CURRENT_TIMESTAMP =", c.execute(u"SELECT CURRENT_TIMESTAMP").fetchone()[0])
实跑输出:
--------------------------------------------------------------------
常量:字符串、数字、日期
--------------------------------------------------------------------
① 数字常量
--------------------------------------------------------------------
| 写法 | 含义 | 算出来 | Python 类型 |
|---|---|---|---|
| 123 | 整数 | 123 | int |
| -45 | 负整数 | -45 | int |
| 3.14 | 小数 | 3.14 | float |
| 1.5e3 | 科学计数,等于 1500 | 1500.0 | float |
| 0x1F | 十六进制,等于 31 | 31 | int |
科学计数法那个 e 不区分大小写,1.5e3 和 1.5E3 一样。
十六进制在 SQL Server 里不是数字字面量,要用 0x 前缀表示二进制常量——
这一点各家不一样,写的时候要先确认用的是哪个库。
② 字符串常量:单引号,里面的单引号写两遍
--------------------------------------------------------------------
| 写法 | 说明 | 取出来 |
|---|---|---|
| 'hello' | 普通字符串 | hello |
| 'it''s' | 含单引号,写两遍 | it's |
| '中文也行' | Unicode 字符 | 中文也行 |
| '<b>' | 尖括号不用转义 | <b> |
字符串一律用单引号,双引号在标准 SQL 里是「标识符」不是字符串。
SQL Server 里双引号包着的默认也当字符串(QUOTED_IDENTIFIER 关掉时),但这是历史包袱。
含单引号的字符串写两遍单引号:'it''s'。这是标准写法,不是反斜杠——
反斜杠转义在 MySQL 里能用,SQL Server 里不行。
③ 日期时间常量:本质还是字符串
--------------------------------------------------------------------
| 写法 | SQLite 存成什么 |
|---|---|
| '2026-10-31' | 2026-10-31 |
| '2026/10/31' | 2026/10/31 |
| '20261031' | 20261031 |
| '2026-10-31 14:30:00' | 2026-10-31 14:30:00 |
SQL Server 里日期常量也是用单引号包着的字符串,由它自己按格式猜。
能认的格式有十几种,但只有 yyyy-MM-dd 和 yyyyMMdd 是「永远安全」的——
因为 '10/11/2026' 这种,在不同语言设置下会被理解成 10 月 11 日或 11 月 10 日。
教材建议写 'yyyyMMdd',就是因为这种写法没有歧义,也不受语言设置影响。
④ 符号常量:那几个 @@ 开头的
--------------------------------------------------------------------
| 常量 | 是什么 | 本沙箱能跑吗 |
|---|---|---|
| @@VERSION | 版本信息字符串 | 不能,SQL Server 专有 |
| @@ROWCOUNT | 上一条语句影响的行数 | 不能 |
| @@IDENTITY | 最后一次插入的自增值 | 不能 |
| @@ERROR | 上一条语句的错误号 | 不能 |
| CURRENT_TIMESTAMP | 当前时间,标准 SQL | 能 |
CURRENT_TIMESTAMP = 2026-10-30 18:47:09
前四个是 T-SQL 的全局变量,严格说不是「常量」——它们会变。
教材把它们归到「符号常量」里,是因为写法上像常量(不需要声明,直接用)。
最后那个 CURRENT_TIMESTAMP 是标准 SQL 的,四家都认,优先用它。
第一段那张表的最后一列最有信息量:0x1F 在这里是整数 31,而在 SQL Server 里是二进制。
同一个字面量、两种含义,这是方言差异里最难察觉的一种。
1.5e3 算出来是 1500.0,类型是 float。 科学计数法一律按浮点处理——所以别用它写金额,
1.5e3 存进 decimal 列会先变成浮点再转,可能带误差。
第二段两行是字符串的重点:'it''s' 取出 it's。 两个单引号变成一个,
这是标准 SQL 的转义方式。反斜杠那种写法在这里行不通。
第三段其实什么也没干——两个日期都原样存成了字符串。因为 SQLite 没有日期类型。
SQL Server 会把它转成 datetime,而转换的结果取决于格式——这就是为什么 'yyyyMMdd' 最安全。
30 秒实验
- 在你的库上执行
SELECT '2026-10-31' + 1(SQL Server),看它返回什么。 它会返回 2026-11-01——日期加一天。 这说明它真把那个字符串当日期解析了。 加一天这件事本身,就是「它认出了这是日期」的证据。 - 再执行
SELECT '20261031' + 1,结果应该一样。这就是「无分隔符最安全」的直接证据。 - 想一想:为什么
N'中文'里的N不能省? 因为它告诉 SQL Server「这是 Unicode 字符串」。 省略之后按当前代码页解析, 某些排序规则下中文会变成问号。
常见误区
- 「字符串可以用双引号」。标准 SQL 里双引号是标识符——包着的是表名列名。 用双引号包字符串,在某些设置下会被当成列名,然后报「列名无效」。一律用单引号。
- 「日期写
'2026/10/31'也能认」。能认,但依赖服务器的语言设置。 换台机器就可能报错或者解析成别的日期。写'20261031'或'2026-10-31',这两种永远安全。 - 「
@@ROWCOUNT就是「上一条语句」的行数」。字面上没错,但中间任何一条语句都会重置它, 包括SELECT @@ROWCOUNT自己。所以要立刻存到自己的变量里。
自测三问(点开对答案)
1. `'it''s'` 取出来是什么? —— **`it's`。** 两个连续的单引号在字符串里表示一个单引号——这是标准 SQL 的转义方式。 反斜杠 `\'` 那种写法只有 MySQL 认,SQL Server 不认。 2. 为什么日期常量推荐写 `'20261031'`? —— **因为无分隔符就无歧义。** `'10/11/2026'` 这种写法, 不同语言设置下会被理解成10 月 11 日或 11 月 10 日——**换台服务器数据就错了一个月。** 3. `0x1F` 在 SQLite 和 SQL Server 里分别是什么? —— **SQLite 里是整数 31;SQL Server 里是二进制常量(1 个字节的值 0x1F)。**同一个写法、 两种含义——**这种差异不会报错,只会让结果不对。**下一篇 6.3 讲变量。
DECLARE 声明、SET 赋值、GO 一分割作用域就断——这是长脚本里「变量未声明」报错的根源。
- ☐ (本篇完,下一篇 6.3 变量)