常规标识符四条硬规则:首字符只能是字母、下划线、at 号、井号;后续可加数字和美元符号;
不能是保留字;不超过 128 字符。
@ 是变量、@@ 是系统函数、# 是局部临时表、## 是全局临时表——前缀不是装饰。
名字里要有空格或保留字,套一层方括号就行;但每次写 SQL 都得套,忘一次就报错。
这一节教材讲得很细,四条规则、三种命名风格、四段式对象名。 看着琐碎,但它是「语法错误」最常见的来源。 真正要带走的是两件事: 一是哪些名字不用引号就能用, 二是「四段式名字」怎么读——后者在跨库查询和链接服务器里天天见。 演示里写了个校验器,把一批候选名挨个判一遍, 再让 SQLite 试着用保留字当列名——它跟 SQL Server 一样认方括号,所以这段能真跑。
一、常规标识符的四条硬规则
所谓「常规标识符」,就是不用加任何括号就能直接写的名字。它有四条硬规则:
1. 首字符:字母、下划线 _、at 号 @、井号 #
2. 后续字符:字母、数字、下划线、at 号、井号、美元符号
3. 不能是 T-SQL 的保留字
4. 长度不超过 128 个字符
这四条里,第一条最容易被忽略。 数字不能开头——2024tb 不行,tb2024 可以。
中文可以开头,因为 SQL Server 的标识符允许 Unicode 字母,「学生表」是个合法名字。
第二条里那个美元符号只准出现在中间和后面。 所以 tb$1 合法,
$tb 不合法——这也是为什么命名实例的服务名是 MSSQL$SQLEXPRESS:美元符号在中间,合规。
第三条是坑最多的一条。 select、from、order、user、key、index 都是保留字,
直接拿来当列名会报语法错误。解决办法不是改名,是加方括号——下一节细说。
二、前缀不是装饰,是分类
| 前缀 | 含义 | 活在哪儿 |
|---|---|---|
| @ | 局部变量 | 当前批处理,出了就没了 |
| @@ | 系统函数 | 全局,如 @@VERSION |
| # | 局部临时表 | 当前连接可见,断开就删 |
| ## | 全局临时表 | 所有连接可见 |
这四个前缀是语法的一部分,不是命名习惯。 看到 @name,编译器就当变量处理,不会去表里找。
所以给表起名叫 @tb 是自找麻烦——能建,但后面查它的时候名字被当成变量了。
@@ 开头的是系统函数,不能自己定义。 你能写 @@VERSION、@@ROWCOUNT,
但不能写 @@MINE——那会报「名称不是可识别的选项」。
# 和 ## 的区别是作用域。 #temp 只有当前连接看得到,连接一断表就没了;
##temp 所有连接都能看到,最后一个用它的人断开之后才消失。
临时表放在 tempdb 里,不是放在你的库。
所以它们不占你的数据文件,也不会被备份——这两点经常有人问「临时表的数据能不能恢复」,答案是不能。
三、保留字当列名:加方括号
方括号是 SQL Server 的「分隔标识符」。 它的意思是「这串字符就是个名字,别当关键字解释」。
演示里让 SQLite 试了一次:不加括号建 CREATE TABLE t1 (select TEXT) 直接报语法错误;
加上括号 CREATE TABLE t1 ([select] TEXT, [order] INT) 就建成了,也能正常查。
四种数据库的分隔符不一样,这是跨库迁移时的第一个坑:
| 数据库 | 分隔符 | 例子 |
|---|---|---|
| SQL Server | 方括号 | [select] |
| SQLite | 方括号或双引号 | [select] 或 select |
| MySQL | 反引号 | select |
| Oracle | 双引号 | select |
不推荐拿保留字当列名。 虽然加括号能用,但从此每一条 SQL 都得加——自己写的记得,ORM 生成的、 报表工具拼的、别人写的不一定记得。一次忘记就报错,而且报得莫名其妙。 真遇到别人设计的库用了保留字,记住一句话:加方括号。 这比改表名安全得多, 改表名要动所有引用它的 SQL、视图、存储过程。
四、四段式对象名怎么读
完整写法是四段,用点隔开:服务器.数据库.架构.对象。举个例子:
SRV01.shop.dbo.tb_goods
| | | |
| | | +-- 表名
| | +-------- 架构(schema)
| +------------- 数据库
+------------------- 服务器(链接服务器才有意义)
四段可以省略,从右往左补默认值。 只写 tb_goods,就是「本机、当前库、dbo、tb_goods」。
写两段 shop.dbo.tb_goods,就是「本机、shop 库、dbo、tb_goods」。
dbo 是架构名,不是用户名。 它默认是数据库所有者,所以绝大多数表都在 dbo 下面。
SQL Server 2005 之前没有架构这一层,这就是老教材里看不到四段名的原因。
写全四段的好处是「换台机器也能跑」。 跨库查询、链接服务器、
同一段脚本在测试库和生产库之间切换,都靠这个。
但写全了迁移时又得改——所以常见的做法是用 USE 库名 切换上下文,SQL 里只写两段。
五、动手 Demo:校验一批候选名,再试保留字
这一段按四条规则写个校验器,把一批候选名挨个判一遍; 再列出四个前缀各自的含义,最后让 SQLite 试一次「保留字当列名」——加方括号和不加,结果完全不同。
import sqlite3
def ok_first(s):
u"""首字符:字母、下划线、at 号、井号"""
return bool(s) and (s[0].isalpha() or s[0] in u"_@#")
def ok_rest(s):
u"""后续:字母、数字、下划线、at 号、井号、美元符号"""
return all(c.isalnum() or c in u"_@#$" for c in s[1:])
RESERVED = {u"select", u"from", u"order", u"user", u"key", u"index"}
for s in (u"tb_student", u"#temp1", u"学生表", u"2024tb",
u"tb-student", u"select"):
print(u"%-12s 首 %-3s 后续 %-3s"
% (s, ok_first(s), ok_rest(s)),
u"能" if (ok_first(s) and ok_rest(s)
and s not in RESERVED) else u"不能")
# 保留字当列名,加不加方括号
c = sqlite3.connect(u":memory:")
try:
c.execute(u"CREATE TABLE t1 (select TEXT)")
except sqlite3.OperationalError as e:
print(u"不加括号:", e)
c.execute(u"CREATE TABLE t1 ([select] TEXT, [order] INT)")
print(u"加方括号:建表成功")
实跑输出:
--------------------------------------------------------------------
命名规则:哪些名字能过
--------------------------------------------------------------------
① 常规标识符的四条硬规则
--------------------------------------------------------------------
1. 首字符:字母、下划线 _、at 号 @、井号 #
2. 后续字符:字母、数字、下划线、at 号、井号、美元符号
3. 不能是 T-SQL 的保留字
4. 长度不超过 128 个字符
| 候选名 | 首字符合法 | 后续合法 | 判断 |
|---|---|---|---|
| tb_student | 是 | 是 | 能 |
| _tmp | 是 | 是 | 能 |
| #temp1 | 是 | 是 | 能 |
| @变量 | 是 | 是 | 能 |
| 学生表 | 是 | 是 | 能 |
| tb2024 | 是 | 是 | 能 |
| 2024tb | 不是 | 是 | 不能 |
| tb-student | 是 | 不是 | 不能 |
| tb student | 是 | 不是 | 不能 |
| select | 是 | 是 | 不能 |
| tb!x | 是 | 不是 | 不能 |
注意中间那几个中文名:「学生表」是合法标识符。
SQL Server 的标识符允许 Unicode 字母,中文、日文都能直接用,不用加引号。
但工程上一般还是用英文加下划线——换编码、换工具的时候少一层麻烦。
② 头和尾那两个符号的意思不一样
--------------------------------------------------------------------
| 前缀 | 含义 | 活在哪儿 |
|---|---|---|
| @ | 局部变量 | 当前批处理里,出了就没了 |
| @@ | 系统函数 | 全局,如 @@VERSION、@@ROWCOUNT |
| # | 局部临时表 | 当前连接可见,断开就删 |
| ## | 全局临时表 | 所有连接可见,最后一个引用断开才删 |
所以 @ 开头的名字是变量,不是表。给表起名叫 @tb 是不行的——
能过语法检查,但你后面 select 它的时候,它被当成变量了。
③ 保留字当列名:加方括号就能过
--------------------------------------------------------------------
不加括号:CREATE TABLE t1 (select TEXT)
near "select": syntax error
加方括号:CREATE TABLE t1 ([select] TEXT, [order] INT)
建表成功,插了一行,查出来是:用方括号过了
方括号是 SQL Server 的「分隔标识符」,意思是「这串字符就是个名字,别当关键字解释」。
SQLite 也认方括号,这一点两边一样;MySQL 用反引号,Oracle 用双引号。
不推荐拿保留字当列名——虽然加括号能用,但每次写 SQL 都得加,忘一次就报错。
④ 四段式对象名
--------------------------------------------------------------------
完整写法:服务器.数据库.架构.对象
例:SRV01.shop.dbo.tb_goods
四段可以省略,从右往左补默认值:只写 tb_goods,就是「本机、当前库、dbo、tb_goods」。
写全四段的好处是「换台机器也能跑」——跨库查询、链接服务器都靠这个。
dbo 是架构名,不是用户名。它默认是数据库所有者,所以绝大多数表都在 dbo 下面。
SQL Server 2005 之前没有架构这一层,这是老教材里看不到四段名的原因。
第一段那个校验器只有二十来行,但把四条规则里的前三条都覆盖了。
第四条(128 字符上限)没写——实际用不到那么长的名字,写进去反而看不清重点。
学生表 判出来是「能」,这跟很多人直觉不一样。 SQL Server 的标识符允许 Unicode 字母,
中文名直接能建,不用加引号。但工程上还是用英文,换工具、换编码的时候少一层麻烦。
tb-student 和 tb student 都是「首字符合法、后续不合法」。这种名字不是不能建——
加方括号就行,但加了之后它就是「分隔标识符」了,每次引用都得加。
第二段是本节的答案。 不加括号报 near "select": syntax error,
加了就过——因为方括号把「关键字」变成了「名字」。
SQLite 认方括号,所以这段能在本地真跑,跟 SQL Server 的行为一致。
30 秒实验
- 用你自己的名字拼音建一张表,比如
zhang_san_test,再试一次zhang-san。 第二次会报错,报的是near "san": syntax error——横线被当成了减号。 - 在 SSMS 里写
SELECT * FROM [select],看它报什么错。 这一行同时演示了两件事:方括号怎么用,以及「名字能过语法但表不存在」是两个不同的错。 - 想一想:为什么
MSSQL$SQLEXPRESS这个名字是合法的? 因为美元符号只能出现在中间和后面,不能开头。 这条规则顺带解释了命名实例的写法。
常见误区
- 「名字随便起,能跑就行」。能跑是暂时的。 带空格、带横线、是保留字的名字,每写一次 SQL 就要加一次括号,换个工具、换个 ORM 就可能漏。 命名规则存在的意义是「少一次出错的机会」。
- 「中文列名不好,必须英文」。技术上没问题,SQL Server 原生支持。 真正的问题在工具链——某些导出工具、某些驱动、某些老版本的客户端对非 ASCII 列名支持不好。 所以是「工程习惯」,不是「技术要求」。
- 「四段名写得越全越专业」。写全了换环境就得改。
日常用
USE切库 + 两段名(dbo.tb),最省事。四段名留给跨库查询和链接服务器。
自测三问(点开对答案)
1. `2024tb` 和 `tb2024` 哪个是合法标识符? —— **`tb2024` 合法,`2024tb` 不合法。** 标识符不能以数字开头—— 因为数字开头的会被当成数字字面量解析,`2024tb` 会被读成「2024 后面跟个 tb」,语法直接崩。 2. `@`、`@@`、`#`、`##` 各是什么? —— **`@` 局部变量,`@@` 系统函数,`#` 局部临时表,`##` 全局临时表。**临时表放在 tempdb 里, 不进你的数据文件,也不被备份——所以里面的数据丢了就丢了。 3. 列名叫 `order`,SQL 里怎么写? —— **写成 `[order]`。** 方括号是 SQL Server 的分隔标识符,意思是「这是名字不是关键字」。 MySQL 用反引号,Oracle 用双引号——跨库迁移时这三种写法要互相换。下一篇 4.3 进正题:建库、改库、删库。
CREATE DATABASE 那段语法教材给得很完整,但真正要理解的是三组参数:初始大小、最大大小、
增长方式——它们决定这个库以后怎么长。
- ☐ (本篇完,下一篇 4.3 数据库的创建与管理)