跳到主要内容

2.4 基础查询

数据存进去了,怎么看?靠 SELECT——它是 SQL 世界里使用频率最高的语句,没有之一。日常开发中,八成以上的 SQL 都是查询。本节从最简单的查询学起:查全部、查指定列、起别名、去重、做点简单运算。所有例子都基于上一节插好的 school 库数据,你可以边看边跑,输出应该和书上一模一样。

📖 本节导读

  • 掌握 SELECT * 查全部列与 SELECT 列名 查指定列
  • 学会用 AS 给列起别名,让结果更好读
  • 学会 DISTINCT 去重
  • 会在查询里做简单算术运算,会查询常量和函数(如 SELECT NOW()

开始前先切换到 school 库:

USE school;

一、查询所有列:SELECT *

语法:

SELECT * FROM 表名;

* 是通配符,表示"所有列"。FROM 指定从哪张表查。整句可以读作:"从 XX 表里,把所有列查出来"。

查学生表:

SELECT * FROM student;
+----+--------+--------+------------+----------+
| id | name | gender | birthday | class_id |
+----+--------+--------+------------+----------+
| 1 | 张三 | 男 | 2005-03-15 | 1 |
| 2 | 李四 | 男 | 2005-07-01 | 1 |
| 3 | 王小红 | 女 | 2006-01-20 | 2 |
| 4 | 赵敏 | 女 | 2005-11-08 | 2 |
| 5 | 陈刚 | 男 | 2006-05-30 | 1 |
+----+--------+--------+------------+----------+
5 rows in set (0.00 sec)

查课程表:

SELECT * FROM course;
+----+--------+---------+
| id | name | teacher |
+----+--------+---------+
| 1 | 数学 | 王老师 |
| 2 | 英语 | 李老师 |
| 3 | 计算机 | 张老师 |
+----+--------+---------+
3 rows in set (0.00 sec)

💡 SELECT * 写起来省事,适合学习和临时排查。但在正式项目代码里建议写明需要的列:一是清晰,二是少传输用不到的数据,性能更好。

二、查询指定列

* 换成列名,多个列用逗号隔开,结果只包含这些列,且按你写的顺序显示:

SELECT name, birthday FROM student;
+--------+------------+
| name | birthday |
+--------+------------+
| 张三 | 2005-03-15 |
| 李四 | 2005-07-01 |
| 王小红 | 2006-01-20 |
| 赵敏 | 2005-11-08 |
| 陈刚 | 2006-05-30 |
+--------+------------+
5 rows in set (0.00 sec)

也可以只查一列:

SELECT name FROM course;
+--------+
| name |
+--------+
| 数学 |
| 英语 |
| 计算机 |
+--------+
3 rows in set (0.00 sec)

三、列别名:AS

查询结果的列标题默认就是列名(如 namebirthday),不够直观。用 AS 可以给列临时起个"外号"(别名),只影响这次查询的显示,不会改动表结构:

SELECT name AS 姓名, birthday AS 出生日期 FROM student;
+--------+------------+
| 姓名 | 出生日期 |
+--------+------------+
| 张三 | 2005-03-15 |
| 李四 | 2005-07-01 |
| 王小红 | 2006-01-20 |
| 赵敏 | 2005-11-08 |
| 陈刚 | 2006-05-30 |
+--------+------------+
5 rows in set (0.00 sec)

两点说明:

  • AS 可以省略,SELECT name 姓名 FROM student; 效果一样。但建议初学阶段都写上,可读性更好。
  • 别名中如果包含空格等特殊字符,要用反引号包起来:SELECT name AS `student name` ...

四、去重:DISTINCT

有时我们只关心"有哪些不同的值"。比如:学生都分布在哪些班?直接查 class_id 会有重复:

SELECT class_id FROM student;
+----------+
| class_id |
+----------+
| 1 |
| 1 |
| 2 |
| 2 |
| 1 |
+----------+
5 rows in set (0.00 sec)

在列名前加 DISTINCT(意为"不同的"),重复值只保留一个:

SELECT DISTINCT class_id FROM student;
+----------+
| class_id |
+----------+
| 1 |
| 2 |
+----------+
2 rows in set (0.00 sec)

再看一个例子——学生有哪些性别:

SELECT DISTINCT gender FROM student;
+--------+
| gender |
+--------+
| 男 |
| 女 |
+--------+
2 rows in set (0.00 sec)

注意:DISTINCT 必须紧跟在 SELECT 后面,作用于后面所有列的组合SELECT DISTINCT gender, class_id FROM student; 去掉的是"性别 + 班级"整体重复的行,而不是分别对两列去重。

五、简单算术运算

SELECT 的列位置不仅能写列名,还能写表达式。支持 +(加)、-(减)、*(乘)、/(除)、%(取余)。

比如老师打算给所有成绩加 5 分平时分,先预览一下加分后的效果(只是查询显示,不会真的修改表中数据):

SELECT id, student_id, course_id, score, score + 5 AS 加分后 FROM score;
+----+------------+-----------+-------+--------+
| id | student_id | course_id | score | 加分后 |
+----+------------+-----------+-------+--------+
| 1 | 1 | 1 | 90.0 | 95.0 |
| 2 | 1 | 2 | 85.0 | 90.0 |
| 3 | 1 | 3 | 88.0 | 93.0 |
| 4 | 2 | 1 | 76.0 | 81.0 |
| 5 | 2 | 2 | 92.0 | 97.0 |
| 6 | 3 | 1 | 95.0 | 100.0 |
| 7 | 3 | 2 | 60.0 | 65.0 |
| 8 | 3 | 3 | 70.0 | 75.0 |
| 9 | 4 | 1 | 58.0 | 63.0 |
| 10 | 4 | 3 | 81.0 | 86.0 |
| 11 | 5 | 2 | 73.0 | 78.0 |
| 12 | 5 | 3 | NULL | NULL |
+----+------------+-----------+-------+--------+
12 rows in set (0.00 sec)

观察最后一行:NULL 加 5 还是 NULL。NULL 表示"未知",未知的数加 5 结果依然未知——这是 NULL 的重要特性,任何值和 NULL 做算术运算,结果都是 NULL。下一节讲 IS NULL 时还会遇到它。

再比如把百分制换算成绩点参考值(除以 10):

SELECT student_id, course_id, score / 10 AS 十分制 FROM score WHERE id = 1;
+------------+-----------+---------+
| student_id | course_id | 十分制 |
+------------+-----------+---------+
| 1 | 1 | 9.00000 |
+------------+-----------+---------+
1 row in set (0.00 sec)

六、查询常量与函数

SELECT 甚至可以不带 FROM,直接算数、查常量——这时它就像一个计算器:

SELECT 1 + 1;
+-------+
| 1 + 1 |
+-------+
| 2 |
+-------+
1 row in set (0.00 sec)

也可以调用函数(MySQL 内置的"小工具",给它输入,它返回结果)。最常用的 NOW() 返回当前日期时间:

SELECT NOW();
+---------------------+
| NOW() |
+---------------------+
| 2026-07-26 10:30:00 |
+---------------------+
1 row in set (0.00 sec)

(你执行时显示的自然是你当时的时间。)常量、函数还能和列名混着写:

SELECT name, '学生' AS 身份, NOW() AS 查询时间 FROM student WHERE id = 1;
+------+------+---------------------+
| name | 身份 | 查询时间 |
+------+------+---------------------+
| 张三 | 学生 | 2026-07-26 10:30:00 |
+------+------+---------------------+
1 row in set (0.00 sec)

更多常用函数(字符串函数、日期函数、数学函数等)会在《查询进阶》章节系统学习。

⚠️ 新手常见坑

  1. 列名之间忘写逗号SELECT name birthday FROM student; 不会报错,但 MySQL 会把 birthday 当成 name 的别名,结果只有一列!多列之间务必用逗号。
  2. 表名写错或没 USE 库:报 Table 'xxx.student' doesn't existNo database selected
  3. 以为 SELECT score + 5 会修改数据:不会。SELECT 只是"看",表中数据分毫未动;真要改数据得用 UPDATE。
  4. DISTINCT 放错位置SELECT class_id DISTINCT ... 是语法错误,DISTINCT 必须紧跟 SELECT。
  5. 中文别名加了单引号:别名不要用单引号(那是字符串的写法),直接写或用反引号。

📝 小结

  • SELECT * FROM 表; 查所有列;SELECT 列1, 列2 FROM 表; 查指定列(正式代码推荐后者)。
  • AS 起列别名,只改显示不改表;AS 可省略但建议写上。
  • DISTINCT 紧跟 SELECT,对后面列的组合去重。
  • SELECT 列表里可以写算术表达式(score + 5)、常量('学生')和函数(NOW());不带 FROM 时是个计算器。
  • NULL 参与任何算术运算,结果都是 NULL。

✍️ 练习题

1. 查询 course 表的所有数据。

参考答案
SELECT * FROM course;

2. 查询所有学生的姓名和性别,并把列标题显示为"姓名"和"性别"。

参考答案
SELECT name AS 姓名, gender AS 性别 FROM student;

3. 查询 course 表中有哪些(不重复的)授课教师。

参考答案
SELECT DISTINCT teacher FROM course;

本例中三位老师本来就不重复,会显示王老师、李老师、张老师三行。

4. 查询每条成绩打九折(乘 0.9)后的值,显示 student_id、course_id、原成绩和打折后成绩(别名"折后")。id=12 那行的"折后"会是多少?

参考答案
SELECT student_id, course_id, score, score * 0.9 AS 折后 FROM score;

id=12 那行原成绩是 NULL,NULL 乘任何数仍是 NULL,所以"折后"显示 NULL。

5. 写一条不带 FROM 的语句,同时显示 100 - 36 的结果和当前时间。

参考答案
SELECT 100 - 36 AS 结果, NOW() AS 当前时间;