字段别名只改输出那一层,表别名是「把原来的名字换掉」,不是追加。
同一张表出现两次,别名是语法强制要求,不起就报「列名有歧义」。
表别名整句都能用,字段别名只能用在 SELECT 之后的子句里。
9.7 只有两个小节:为表取别名、为字段取别名。语法极简,但可见范围容易记错。 这一篇和 9.1 的执行顺序是同一件事的两面:9.1 用别名去验顺序,这里讲别名本身。
一、字段别名
字段别名的作用是改结果集的列名,表里的列名一点没变。 所以它只发生在输出那一层,不改变任何数据。
SELECT price * 1.1 AS 新价, price * 1.1 "新 价" FROM tb_goods;
AS 可以不写,直接空格加别名也行。
别名里有空格或中文,得用双引号包起来,不然会被当成两个词。
MySQL 里通常写反引号,沙箱里认双引号——这是引号习惯的差异,不是语义差异。
跨库搬 SQL 时这一处最容易被改坏,因为两边的引号规则不一样。
字段别名最实际的用处是给计算列起名。
price * 1.1 这种列在结果集里没有名字,导出报表时就是一片空白。
二、表别名
表别名是给整张表起个短名字,好处是少打字,尤其是列名长、表名也长的时候。
它更大的用处是「同一张表出现两次时区分开」。
一旦给表起了别名,原表名在这一句里就不能再用了。
写 SELECT tb_emp.name FROM tb_emp e 会报 no such column。
所以别名不是「再额外加一个名字」,而是「把原来的名字换掉」。
这一点和字段别名不一样:字段别名是并列的,原名和新名都在。
三、为什么自连接必须起别名
同一张表并排放两次,引擎没法区分「这一列是哪一张的」。
不起别名时,SELECT name FROM tb_emp, tb_emp 报 ambiguous column name: name。
这不是风格问题,是语法要求。
所以看到自连接,第一件事就是给它俩各起一个短名字:e 和 m,员工和上级。
别名起得好的自连接,读起来像两张不同的表。
起得差(比如 t1 t2),读的人得反复回看 ON 才知道谁是谁。
四、别名盖住原列名时会怎样
别名和原列名重名是允许的,而且排在 SELECT 之后的子句里,别名优先。
所以 SELECT price AS stock, stock FROM tb_goods ORDER BY stock 排的是 price。
想排真正的 stock 列,得写 ORDER BY 2(按列序号),结果立刻不一样。
这种写法本身就该避免:查错数据时最难查的就是「名字一样、意思不同」。
别名要么改得不像列名,要么干脆别用。
五、两种别名的可见范围
表别名在整句里都能用,WHERE 里也行,因为它是在 FROM 那一层就绑定的。
字段别名不一样,它是在 SELECT 那一层才产生的。
沙箱里字段别名放到 WHERE、GROUP BY、ORDER BY 都能用,因为 SQLite 放宽了标准。
换成 MySQL,WHERE 里会报 Unknown column 'p' in 'where clause'。
| 别名放在哪 | 沙箱 | MySQL |
|---|---|---|
表别名放 WHERE |
能用 | 能用 |
字段别名放 WHERE |
能用 | 报错 |
字段别名放 ORDER BY |
能用 | 能用 |
字段别名放 GROUP BY |
能用 | 能用 |
按 MySQL 记就行:表别名哪里都能用,字段别名只能用在 SELECT 之后的子句。
WHERE 在 SELECT 之前,用不了;ORDER BY 在之后,能用。
记不住顺序就记一句话:WHERE 筛的是「行」,那时还没算别名。
这句话和第 9.1 篇讲执行顺序时说的是同一句,别名只是它的一个推论。
六、动手 Demo:两种别名,和它们各自的可见范围
这一段有一组对照特别值得看:同一个别名放在四种位置,沙箱说四个都能用,而 MySQL 只有一个不让。
import sqlite3
c = sqlite3.connect(u"d042.db")
# ① 字段别名:AS 可省,带空格要引号
c.execute(u"SELECT price * 1.1 AS 新价, price * 1.1 \"新 价\" FROM tb_goods").fetchall()
# ② 同一张表两次,别名强制
for sql in [u"SELECT name FROM tb_emp, tb_emp",
u"SELECT e.name, m.name FROM tb_emp e, tb_emp m",
u"SELECT tb_emp.name FROM tb_emp e"]:
try:
c.execute(sql).fetchall()
print(u"成功", sql)
except sqlite3.OperationalError as e:
print(u"报错", e)
# ③ 别名盖住原列名
c.execute(u"SELECT price AS stock, stock FROM tb_goods ORDER BY stock DESC").fetchall()
c.execute(u"SELECT price AS stock, stock FROM tb_goods ORDER BY 2 DESC").fetchall()
实跑输出:
--------------------------------------------------------------------
第四十二课:两种别名,和它们各自的可见范围
--------------------------------------------------------------------
**教材 9.7 讲为表和字段取别名。别名的用处是「少打字」和「改显示名」。**
**但两种别名的可见范围不一样,这一点比语法重要。**
一、字段别名:AS 可以省,空格要引号
--------------------------------------------------------------------
新价 新 价
----------
1.87 1.87
2.64 2.64
2 rows in set
**`AS` 是可以不写的,直接空格加别名也行。**
**别名里有空格或中文,得用双引号包起来,不然会被当成两个词。**
**别名只影响结果集的列名,表里的列名一点没变。**
**所以「改名字」这件事只发生在输出那一层。**
二、表别名:长名字的救星
--------------------------------------------------------------------
id code name
--------------
1 G00001 数码
2 G00002 家电
3 G00003 服饰
3 rows in set
**表别名一取,整句都能用 `g.` `k.` 这种短前缀。**
**一旦给表起了别名,原表名在这一句里就不能再用了——这是常被忽略的规矩。**
三、同一张表出现两次,别名是强制的
--------------------------------------------------------------------
写法 结果
-----------------------------------------------------
不起别名 报错:ambiguous column name: name
起了别名 成功
起了别名又用原表名 报错:no such column: tb_emp.name
**第一行报 `ambiguous column name: name`——两张同名表并排放着,`name` 是谁的说不清。**
**这就是自连接必须给两个别名的原因,不是风格问题,是语法要求。**
**第三行更值得记:起了别名之后原表名就不认了,报 `no such column`。**
**所以别名不是「再额外加一个名字」,而是「把原来的名字换掉」。**
四、别名和原列名重名时,谁优先
--------------------------------------------------------------------
stock stock
-----------
200.9 357
200.9 357
200.9 357
3 rows in set
stock stock
-----------
150.3 499
100.3 499
50.3 499
3 rows in set
**两句的结果不一样,差别只在 `ORDER BY` 后面写的是名字还是序号。**
**写 `stock` 排的是别名(也就是 price),写 `2` 排的是真正的第 2 列。**
**所以「别名盖住原列名」是允许的,而且排在前面的子句里会优先用别名。**
**这种写法本身就该避免——查错数据时最难查的就是这种「名字一样、意思不同」。**
五、表别名整个语句都能用,字段别名不一定
--------------------------------------------------------------------
别名放在哪 本沙箱的结果
-----------------------------------
表别名放 `WHERE` 能用
字段别名放 `WHERE` 能用
字段别名放 `ORDER BY` 能用
字段别名放 `GROUP BY` 能用
**沙箱里四行都能用,因为 SQLite 对字段别名格外宽松。**
**换成 MySQL,第二行会报 `Unknown column 'p' in 'where clause'`。**
**所以这条要按 MySQL 记:表别名哪里都能用,字段别名只能用在 `SELECT` 之后的子句里。**
**`WHERE` 在 `SELECT` 之前,用不了;`ORDER BY` 在之后,能用。**
**记不住顺序就记一句话:`WHERE` 筛的是「行」,那时还没算别名。**
自连接那三行是这一课的骨架:报「列名有歧义」、成功、报「没有这一列」。
第三行最容易被忽略——起了别名之后,原表名就不认了。
ORDER BY 那两句只差一个写法,ORDER BY stock 排的是 price,
ORDER BY 2 排的是真正的第 2 列。
第一句的三行全是 200.9 / 357,说明它按 price 从大到小取了三行,
而 stock 那列的值一直是 357——两列被完全解耦了。
第二句的三行是 150.3、100.3、50.3,这才是在按 stock 排。
同一个结果集,两个排序写法给出完全不同的顺序,这就是「别名盖住原列名」的后果。
30 秒实验
- 把
SELECT price AS stock的别名改成p,看ORDER BY p和ORDER BY stock的区别。 - 把
tb_emp e, tb_emp m的别名去掉,确认它报列名歧义。 - 在有别名的句子里写原表名,确认它报
no such column。
常见误区
- 给表起了别名又用原表名,报「没有这一列」还以为是拼写错。
- 自连接不起别名,报「列名有歧义」。
- 用别名覆盖了同名的原列,
ORDER BY排出来不是自己想要的,还不容易发现。
自测三问(点开对答案)
1. 表别名和字段别名的本质区别是什么? —— 表别名是「替换」原表名,起了之后原名不能再用; 字段别名是「追加」,原名还在,只是结果集里多了一个名字。 2. 自连接为什么必须起两个别名? —— 因为同一张表出现两次,引擎无法区分列属于哪一次引用。 不起别名会报列名有歧义,这是语法要求,不是风格问题。 3. MySQL 里字段别名能不能用在 `WHERE` 里? —— 不能,会报 `Unknown column`。因为 `WHERE` 在 `SELECT` 之前执行,那时别名还不存在。最后一篇 9.8 讲正则查询,包括它在沙箱里怎么找替身。
- ☐ (本篇完,下一篇 9.8 使用正则表达式查询)