# MySQL教程 - 7 查询

下面开始重头戏,查询!在 SQL 分类中属于 DQL(Data Query Language,数据查询语言)。

查询操作是 SQL 中的重中之重, 在 SQL 操作中,80% 的操作都是在查询表中数据,我们会根据查询条件进行查询,并对数据进行排序等操作。

话不多说,开始。

首先看一下查询的语法:

SELECT 字段列表
FROM 表名列表
WHERE 条件列表
GROUP BY 分组字段列表
HAVING 分组后条件列表
ORDER BY 排序字段列表
LIMIT 限制查询数量
1
2
3
4
5
6
7

上面看着有点复杂,没关系,慢慢一个一个讲解。


首先准备一下数据,这里执行如下 SQL,向 tb_employee 表插入一些数据,你可以拷贝执行:

-- 先清空一下表
TRUNCATE TABLE tb_employee;

-- 插入数据
INSERT INTO tb_employee (emp_number, name, id_card, age, gender, salary, entry_time) VALUES
('1', '罗辑', '110101198001010011', 42, '男', 12000.50, '2022-03-15 10:30:00'),
('2', '叶文洁', '110101195502020022', 68, '女', 15000.00, '2022-05-20 14:45:00'),
('3', '程心', '110101199003030033', 25, '女', 28000.75, '2023-01-10 09:00:00'),
('4', '史强', NULL, 48, '男', 8000.00, '2022-08-22 16:10:00'),
('5', '庄颜', NULL, 30, '女', 13000.25, '2023-04-05 18:20:00'),
('6', '云天明', '110101198707070066', 35, '男', 18000.00, '2024-06-14 11:45:00'),
('7', '维德', '110101198303030077', 40, '男', 16000.80, '2023-03-02 08:15:00'),
('8', '艾AA', '110101199501050088', 28, '女', 39500.60, '2024-07-07 13:30:00'),
('9', '丁仪', '110101196802080010', 54, '男', 24500.35, '2023-02-11 10:00:00'),
('10', '章北海', '110101197012100011', 50, '男', 19000.90, '2023-01-28 14:00:00'),
('11', '杨冬', '110101199203150012', 31, '女', 12500.00, '2022-11-30 09:15:00'),
('12', '汪淼', '110101198509200013', 38, '男', 14000.50, '2023-05-16 12:00:00'),
('13', '常伟思', '110101197408250014', 54, '男', 11000.00, '2022-10-20 11:00:00'),
('14', '关一帆', '110101199406060015', 28, '男', 10500.70, '2024-06-22 16:45:00'),
('15', '伊文斯', '11010119760309001X', 47, '男', 57500.25, '2023-03-30 13:00:00');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 7.1 检索数据

# 1 查询所有字段

查询表中所有的数据,如下:

SELECT *
FROM tb_employee;
1
2
  • SELECT * 表示查询表中所有的字段;
  • FROM tb_employee 指定从哪张表中查询;

执行结果:

id emp_number name id_card age gender salary entry_time
1 1 罗辑 110101198001010011 42 12000.50 2022-03-15 10:30:00
2 2 叶文洁 110101195502020022 68 15000.00 2022-05-20 14:45:00
3 3 程心 110101199003030033 25 28000.75 2023-01-10 09:00:00
...略

# 2 查询指定字段

SELECT * 会返回表中所有列,哪怕有些列你并不需要。这可能导致网络传输的开销增大,尤其是在表字段多或数据量大的情况下。所以一般在实际使用是不推荐使用 SELECT *

一般都是需要哪些列查询哪些列,所以就需要指定查询的列:

-- 查询表中所有数据,并指定查询的列
SELECT id, emp_number, name, id_card, age, gender
FROM tb_employee;
1
2
3
  • 在 SELECT 后指定查询的列,使用 , 分隔。

执行结果:

id emp_number name id_card age gender
1 1 罗辑 110101198001010011 42
2 2 叶文洁 110101195502020022 68
3 3 程心 110101199003030033 25
...略

# 3 查询别名

查询别名(Alias) 是指查询的时候,可以为字段指定一个别名,提高可读性。在多表连接查询(后面讲)时,可以避免字段名重复。

举个栗子:

-- 为字段设置别名
SELECT id, name as 'employee_name', id_card as '身份证', age, gender
FROM tb_employee;
1
2
3
  • 上面在查询的时候,通过 as 关键字,可以为字段设置别名;
  • 其实 as 关键字可以省略的,例如写为 SELECT name 'employee_name', id_card '身份证' 即可。

执行结果如下,列的名称变了:

id employee_name 身份证 age gender
1 罗辑 110101198001010011 42
2 叶文洁 110101195502020022 68
3 程心 110101199003030033 25
...略

# 4 去除重复的查询记录

有时候查询出的结果会存在重复,例如查询所有数据的年龄:

SELECT age FROM tb_employee;
1

结果肯定是存在重复的,那么可以使会用 DISTINCT 关键字去重:

SELECT DISTINCT age
FROM tb_employee;
1
2
  • 通过添加 DISTINCT 关键字,结果会去掉重复数据。

# 7.2 查询条件

上面在查询的时候,没有指定查询条件,那么会查询所有的数据,一般在查询的时候,都会通过 WHERE 子句执行查询条件。

SELECT 字段列表
FROM 表名列表
WHERE 条件列表
1
2
3

举个栗子:

-- 查询 name 为 '罗辑' 的员工信息
SELECT * 
FROM tb_employee
WHERE name = '罗辑';
1
2
3
4
  • 通过 WHERE 指定查询条件,只查询需要的数据。
  • 因为 name 字段是字符串,那么需要使用 '' 将值括起来,数字类型的不用;

执行结果:

id emp_number name id_card age gender salary entry_time
1 1 罗辑 110101198001010011 42 12000.50 2022-03-15 10:30:00

# 1 比较运算符

上面演示的时候,使用了 name = '罗辑' ,使用的是 等于(=) 比较运算符,还有以下运算符可以使用:

运算符 描述
= 等于
<> 或 != 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于

举个栗子:

-- 查询年龄大于等于35的员工
SELECT * FROM tb_employee WHERE age >= 35;

-- 查询年龄不等于35的员工
SELECT * FROM tb_employee WHERE age != 35;
1
2
3
4
5

# 2 逻辑运算符

上面查询的时候,只设置了一个查询条件,查询条件是可以设置多个的,可以通过逻辑运算符连接多个查询条件。

逻辑运算符有如下几个:

运算符 描述
AND 同时满足多个条件
OR 满足任意一个条件
NOT 对条件取反

举个栗子:

-- 查询年龄大于30,并且小于40的员工
SELECT * FROM tb_employee WHERE age > 35 and age < 40;

-- 查询年龄大于35,并且是女性的员工
SELECT * FROM tb_employee WHERE age > 35 AND gender = '女';

-- 查询年龄大于40,或者年龄小于30的员工
SELECT * FROM tb_employee WHERE age > 40 OR age < 30;

-- 查询年龄等于30或40或50的员工,可以多个拼接
SELECT * FROM tb_employee WHERE age = 30 OR age = 40 OR age = 50;

-- 查询年龄不大于35岁的员工,也就是小于等于35,一般不这样用
SELECT * FROM tb_employee WHERE not age > 35;
-- 等价于
SELECT * FROM tb_employee WHERE age <= 35;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

逻辑运算符是有优先级的,NOT > AND > OR

举个栗子:

-- 查询年龄大于40或者年龄小于30的女性员工
SELECT * FROM tb_employee WHERE (age > 40 OR age < 30) and gender = '女';
1
2
  • 年龄大于40或者年龄小于30是一个条件,因为 OR 的优先级小于 AND,所以使用括号括起来,否则会查询 年龄大于40的员工 或者 年龄小于30的女性员工

# 3 范围查询

用于检查某个值是否在指定范围内,包含边界 ,可以使用 BETWEEN ... AND ...

举个栗子:

-- 查询年龄在30和40之间的员工,包括30和40
SELECT * FROM tb_employee WHERE age BETWEEN 30 AND 40;

-- 效果等价于
SELECT * FROM tb_employee WHERE age >= 30 AND age <= 40;
1
2
3
4
5
  • 注意 AND 前面是小值,AND 后面是大值,否则查询不到结果。

# 4 集合查询

查询字段是属于指定集合中的记录,如果 OR 的个数比较多,可以使用集合查询。

举个栗子:

-- 查询年龄是30,40,50或60的员工
SELECT * FROM tb_employee WHERE age = 30 OR age = 40 OR age = 50 OR age = 60;

-- OR的条件太多,可以使用in()查询
SELECT * FROM tb_employee WHERE age IN (30, 40, 50, 60);
1
2
3
4
5

还可以搭配 NOT 查询,查询不在指定集合中的记录:

-- 查询年龄不等于30,40,50,60的员工
SELECT * FROM tb_employee WHERE age NOT IN (30, 40, 50, 60);
1
2

# 5 模糊查询

模糊查询是用于匹配部分字符串的查询方式。

模糊查询使用 LIKE 关键字,通常结合通配符使用:

  • %:匹配任意数量的字符(包括 0 个字符)。
  • _:匹配单个任意字符。

举个栗子:

-- 查询身份证号是 110101198 开头的员工,右模糊查询
SELECT * FROM tb_employee WHERE id_card LIKE '110101198%';
1
2
  • '110101198%' 表示 110101198 开头,后面跟0个或任意个字符。
-- 查询身份证号码中以 110 开头,2结尾的员工
SELECT * FROM tb_employee WHERE id_card LIKE '110%2';

-- 查询身份证号码最后一位是X的员工,左模糊查询
SELECT * FROM tb_employee WHERE id_card LIKE '%X';

-- 查询身份证号码中中包含1983的员工,前后都使用%
SELECT * FROM tb_employee WHERE id_card LIKE '%1983%';
1
2
3
4
5
6
7
8

需要注意,一般不太推荐使用左模糊查询'%xx' ),因为会扫描表中所有的记录进行匹配,在数据量大的时候,性能不好。


如果只想跟一个字符,可以使用 _ 通配符,举个栗子:

查询名字以 开头,并且名字是两个字的员工。

-- 以姓程的,名字是两个字的员工
SELECT * FROM tb_employee WHERE name LIKE '程_';

-- 查询名字第二个字是'强'的员工
SELECT * FROM tb_employee WHERE name LIKE '_强%';

-- 查询名字是两个字的员工,使用两个_
SELECT * FROM tb_employee WHERE name LIKE '__';
1
2
3
4
5
6
7
8

# 6 空值检查

IS NULL 用于判断列的值是否为 NULL

举个栗子:

-- 查询身份证号码为空的员工
SELECT * FROM tb_employee WHERE id_card IS NULL;

-- 查询身份证号码不为空的员工,使用NOT取反
SELECT * FROM tb_employee WHERE id_card IS NOT NULL;
1
2
3
4
5

# 7.3 查询结果排序

对查询结果排序在实际的开发中是必不可少的,例如商品按照价格排序、订单按照创建时间倒序排序等。

对查询结果排序,使用 ORDER BY 关键字,语法如下:

SELECT 字段列表
FROM 表名
ORDER BY 字段1 排序方式, 字段2 排序方式, ...
1
2
3

排序方式有两种方式:升序(ASC)降序(DESC),排序方式可以省略,省略默认为升序。


# 1 单个字段排序

举个栗子:

-- 查询所有员工,按照工资升序排列
SELECT * FROM tb_employee ORDER BY salary ASC;

-- ASC可以省略,默认升序
SELECT * FROM tb_employee ORDER BY salary;
1
2
3
4
5

执行结果:


降序排列:

-- 查询所有员工,按照工资降序排列
SELECT * FROM tb_employee ORDER BY salary DESC;
1
2

# 2 多个字段排序

排序可以按照多列进行排序,在进行多列排序的时候,会将结果先按照第一列排序,第一列相同的情况下,再按照第二列排序。

例如:先按照性别升序排列,然后按照工资升序排列:

-- 按照性别和工资排序
SELECT * FROM tb_employee ORDER BY gender, salary;

-- 或者使用
SELECT * FROM tb_employee ORDER BY gender, salary ASC;

-- 或者使用
SELECT * FROM tb_employee ORDER BY gender ASC, salary ASC;
1
2
3
4
5
6
7
8
  • 会先按照性别升序排序,性别相同的情况下,按照工资升序排序。

执行结果:


再举个栗子:

按照年龄升序排序,如果年龄相同,按照入职时间降序排列:

SELECT * FROM tb_employee ORDER BY age ASC, entry_time DESC;
1