SELECT 基础与列/表别名
本教程共 50 篇 · 第 22 篇 · 更新于 2026-07-31 · 约 8 分钟阅读
22. SELECT 基础与列/表别名
本节目标:学完你能用 SELECT 取出想要的列、给列和表达式起好懂的别名,也知道 SELECT * 的适用边界,还懂得 NULL 参与运算、以及列别名不能在 WHERE 里用的坑。
查询(SELECT)是平时用得最多的语句,作用是从表里「读」数据。它不改任何数据,只返回结果。
先放几条数据:
INSERT INTO users (username, email, age)
VALUES
('xiaoming', 'ming@example.com', 28),
('xiaohong', 'hong@example.com', 22),
('wangwu', 'wang@example.com', 35);
在 psql 里执行查询,提示符和结果长这样:
postgres=# SELECT username, age FROM users;
username | age
----------+-----
xiaoming | 28
xiaohong | 22
wangwu | 35
(3 rows)
选指定的列
想看哪些列,就把列名写在 SELECT 后面,用逗号隔开:
SELECT username, age
FROM users;
只返回用户名和年龄两列。
取全部列(SELECT *)
* 是「所有列」的简写:
SELECT * FROM users;
Warning把
SELECT *写进应用程序代码里不是好习惯。表一加列,程序可能收到意料之外的字段;而且它永远把整行读出来,数据多时浪费带宽。临时在 psql 里瞅数据用*没问题,正式代码里建议把列名写全。
给列起别名(AS)
列名太长或不直观时,用 AS 起个临时的「别名」,只在这次查询里生效。
SELECT
username AS 用户名,
age AS 年龄
FROM users;
AS 可以省略,写成 username 用户名 也行,但我建议保留 AS,读起来更清楚。
表达式列
SELECT 后面不只能是列名,还可以是算出来的表达式。下面把年龄加 1 作为「明年年龄」:
SELECT
username,
age,
age + 1 AS 明年年龄
FROM users;
字符串也能拼接。PostgreSQL 用 || 把字符串连起来:
SELECT
username || ' 的邮箱是 ' || email AS 简介
FROM users;
如果不写别名,表达式列会显示成 ?column? 这种怪名字,所以建议都起个别名。
别名带空格要加引号
别名里含空格时,要用双引号包起来:
SELECT age + 1 AS "明年 年龄"
FROM users;
Note这里用的是双引号
",不是单引号。单引号在 SQL 里表示字符串,双引号才表示标识符(比如列名、别名)。
NULL 参与的运算
这一点很多人第一次遇到会懵:任何值和 NULL 做算术,结果还是 NULL。比如某行的 age 是 NULL,那 age + 1 也会是 NULL,不是 0,也不是 1。
SELECT
username,
age,
age + 1 AS 明年年龄
FROM users;
如果某行 age 为空,它的「明年年龄」也会是空。记住:NULL 表示「未知」,和未知相加,结果依然是未知。
用常量和函数当列
SELECT 后面还能放常量或函数调用,结果会作为一列返回。比如加一列欢迎语,或算名字长度:
SELECT
username,
'hello' AS 问候,
length(username) AS 名字长度
FROM users;
length() 返回字符串的字符数,常用来做长度校验或展示。
不查表也能 SELECT
SELECT 后面不一定非得跟 FROM。比如直接拿当前时间:
SELECT now();
这在测试函数、算个表达式时很方便,不需要任何表参与。
表别名
查询里还能给表起别名,写法也是 表名 AS 别名。单表查询时图省事用一下:
SELECT u.username, u.age
FROM users AS u;
表别名真正的用武之地是多表连接(JOIN)和自连接,那边表名要重复写很多次,起个短别名 u、o 会清爽很多。这里先知道有这么回事,连接章节再细讲。
常见错误
- 把列别名用在 WHERE 里:下面这样会报错,因为 WHERE 在 SELECT 之前执行,还没生成「名字」这个别名:
正确写法是在 WHERE 里用原列名:-- 错误写法 SELECT username AS 名字, age FROM users WHERE 名字 = 'xiaoming';WHERE username = 'xiaoming'。 - 别名重复:给两列起了同样的别名,结果集会分不清,建议别重名。
- 生产代码用 SELECT *:表结构一变就出问题,字段名要写全。
表达式里的运算顺序
表达式列里也能用括号控制优先级,和数学里一样。下面两种写法结果不同:
SELECT
username,
age + 1 * 2 AS 写法一,
(age + 1) * 2 AS 写法二
FROM users;
age + 1 * 2 先算乘法,等于 age + 2;(age + 1) * 2 先加后乘。不确定顺序时,加括号最稳。
布尔结果也能当列
SELECT 后面可以放一个比较,结果是一列 true / false。比如判断用户是否「资深」(年龄大于 30):
SELECT
username,
age,
age > 30 AS 是否资深
FROM users;
返回的「是否资深」列就是布尔值,常用来在结果里直接打标记,或给上层程序做判断。
Note布尔列(
true/false)也能起别名,建议起个好懂的中文名,比如上面的「是否资深」,读结果时一眼就明白。
用「表名.列名」限定
当查询涉及多张表、列名可能重名时,要用 表名.列名 把列说清楚:
SELECT users.username, orders.amount
FROM users, orders
WHERE users.id = orders.user_id;
这种「表名.列名」的写法在多表查询里几乎是必须的,能避免「列名有歧义」的报错。单表查询里不写也行,写了更严谨。
选择列的顺序随你定
SELECT 后面列的顺序,决定结果里列的先后,和表定义无关。下面把 age 放前面也完全合法:
SELECT age, username, email
FROM users;
想先看哪列就看哪列,顺序你定。
一次写多个表达式列
表达式列可以写好几个,互相独立。比如同时算「明年年龄」和「大概出生年」:
SELECT
username,
age + 1 AS 明年年龄,
2026 - age AS 大概出生年
FROM users;
2026 - age 是个简单减法,结果作为新列返回。注意 age 为 NULL 时,这两列也都会是 NULL。
别名还能在排序里复用
起好别名后,后面的「排序」章节你会看到,可以直接按别名排序,比如 ORDER BY 明年年龄。这里先记住:别名是这次查询里的临时名字,排序、分组时常会再用到它。
表达式列里也能嵌套函数
表达式不限于加减和拼接,还能套函数。比如把用户名转大写、再算长度:
SELECT
username,
upper(username) AS 大写名,
length(username) AS 名字长度
FROM users;
upper() 把字母转成大写(中文不受影响),length() 返回字符数。函数章节会系统讲,这里先知道:表达式列里什么都能往里塞。
小结
SELECT 列... FROM 表取指定列;SELECT *取全部列。- 用
AS给列、表达式、表起临时别名,提升可读性。 - 表达式也能当列返回,记得起别名,否则列名叫
?column?。 - 任何值和 NULL 运算结果仍是 NULL。
- 带空格的别名用双引号包起来;列别名不能在 WHERE 里用;正式代码里优先写全列名,少用
*。