SELECT 基础语法

上一篇我们认识了 SQL 的来龙去脉,这一篇正式开始写代码。SELECT 是 SQL 里你写得最多的语句——日常开发 80% 的 SQL 都是查询,所以先把 SELECT 的基本骨架打扎实。

1. SELECT 的基本结构

SELECT 语句的核心作用是:从一张表里取出某些列的某些行。最小可运行的 SELECT 长这样:

-- SELECT 是 SQL 里你写得最多的语句,用来"查数据"
-- 最简单的形式:从一张表里取某些列的某些行
SELECT name, age FROM students;
-- 关键字大小写不敏感:select Name AGE 也是合法的
-- 但约定俗成关键字大写、表名/列名小写,可读性更好

关键字大小写不敏感(selectSelectSELECT 都合法),但工程约定俗成关键字大写、表名列名小写,这样一眼能分清"哪些是 SQL 语法、哪些是业务字段"。

2. 星号(SELECT *)

初学者最爱写 SELECT *,它表示"取所有列"。看着方便,但工程里强烈不推荐:

-- 星号 * 表示"所有列"
SELECT * FROM students;
-- ⚠️ 工程里不推荐,原因:
-- 1. 表加字段后 * 语义变化,可能破坏前端
-- 2. 浪费带宽(也许你只需要 2 列,却传了 20 列)
-- 3. 索引可能用不上(无法形成覆盖索引)

-- 推荐:明确写出要的列
SELECT id, name, email FROM students;

养成习惯:只 SELECT 真正需要的列。这既是为了性能,也是为了代码的可维护性——表加字段后,明确列名的查询语义不变,而 SELECT * 可能悄悄改变结果集结构。

3. 列别名(AS)

AS 给列或表起一个临时别名,结果集里就会用新名字。在表达式列(比如 COUNT(*))、JOIN 表别名场景下几乎必用:

-- 用 AS 给列起别名(结果集的列名会变成新名字)
SELECT name AS student_name, age AS student_age FROM students;

-- AS 可以省略,但加上更清晰
SELECT name student_name FROM students;

-- 给表起别名(JOIN 里几乎必用)
SELECT s.name, s.age
FROM students AS s
WHERE s.age > 20;

-- 别名带空格或特殊字符时,要用双引号或反引号包起来
SELECT name AS "学生姓名" FROM students;

注意:别名带空格或中文时,要用双引号(标准)或反引号(MySQL)包起来,否则数据库会把它当成多个标识符解析报错。表别名通常用单字母缩写(users uorders o),让 SQL 短小精悍。

4. DISTINCT 去重

有时你只关心"有哪些不同的值",而不是"所有行"。这时用 DISTINCT 关键字:

-- DISTINCT 去重:返回唯一不同的值
-- 比如学生来自哪些城市?
SELECT DISTINCT city FROM students;

-- 多列去重:city + age 组合唯一
SELECT DISTINCT city, age FROM students;

-- 注意:DISTINCT 性能开销大,大数据量慎用
-- 替代方案:GROUP BY 通常更灵活,见 group-by 篇

DISTINCT 会对结果集做去重(底层类似排序+合并),性能开销不小。如果只是为了去重统计数量,推荐用 GROUP BYCOUNT(DISTINCT col),后面会专门讲。

5. 注释

SQL 的注释分单行和多行,和大部分语言一样:

-- 这是单行注释,双横杠开头(MySQL 要求横杠后有空格)

/* 这是多行注释,
   可以跨多行,
   用斜杠星号包裹 */

/* MySQL 特有:行内注释,井号开头 */
SELECT name, age  # 查所有学生的姓名和年龄
FROM students;

/* 在 SQL 里写注释是好习惯:
   - 复杂查询要解释意图
   - 临时禁用某段 WHERE 条件
   - 给后人留 context */

实战中写注释是好习惯,尤其是复杂查询。我见过 200 行的 SQL 一行注释都没有,接手的人(包括三个月后的作者本人)看完直接怀疑人生。

6. 字面量与表达式

SELECT 后面不一定要是列名,也可以是字面量、表达式或函数调用:

-- SELECT 后面不一定非要跟列,也可以是字面量或表达式
SELECT 1 + 1;                    -- 返回 2
SELECT NOW();                    -- 返回当前时间
SELECT VERSION();                -- 返回数据库版本
SELECT 'hello' AS greeting;     -- 返回固定字符串

-- 实战:给所有结果加一个固定标记列
SELECT id, name, 'active' AS status FROM users;

这个用法在给结果集加固定标记列时特别有用——比如导出 CSV 时给每行加一个 'active' 状态字段,方便下游处理。

7. 分号与字符串引号

两个新手常踩的坑:

-- 每条 SQL 语句以分号结尾(部分客户端可省略,但建议总是写)
SELECT * FROM students;

-- 多条语句可以连写
INSERT INTO students (name) VALUES ('小明');
SELECT * FROM students;

-- 字符串用单引号,不是双引号!
SELECT * FROM students WHERE name = '小明';   -- ✅ 正确
SELECT * FROM students WHERE name = "小明";   -- ⚠ MySQL 容忍但标准不推荐

字符串用单引号是 SQL 标准;双引号在标准里表示"标识符"(表名/列名),MySQL 容忍双引号字符串但 PostgreSQL 严格区分。'it\'s' 这种含撇号的字符串,用反斜杠转义或双写单引号 'it''s'

小结

这一篇你学会了 SELECT 的基本骨架:选哪些列(SELECT)、从哪张表(FROM)、起别名(AS)、去重(DISTINCT)、注释写法。下一篇我们看 DDL——如何创建一张表,这是用 SQL 之前必须先做的事。

← 上一篇 SQL 简介

下一篇 DDL 数据定义

✈️💬