目录
[1. insert 新增](#1. insert 新增)
[1.0 前期准备](#1.0 前期准备)
[1.1 全列插入](#1.1 全列插入)
[1.2 指定列插入](#1.2 指定列插入)
[1.3 同时插入多行数据](#1.3 同时插入多行数据)
[2. select 查询](#2. select 查询)
[2.0 示例的数据准备](#2.0 示例的数据准备)
[2.1 基础查询](#2.1 基础查询)
[1. 全列查询](#1. 全列查询)
[2. 指定列查询](#2. 指定列查询)
[3. 表达式的查询](#3. 表达式的查询)
[4. 字段的别名](#4. 字段的别名)
[5. 结果去重查询](#5. 结果去重查询)
[3. where 查询](#3. where 查询)
[3.1 mysql的比较运算、逻辑运算](#3.1 mysql的比较运算、逻辑运算)
[3.2 比较查询](#3.2 比较查询)
[3.3 模糊查询](#3.3 模糊查询)
[3.4 区间(范围)查询](#3.4 区间(范围)查询)
[3.5 判空(null)查询](#3.5 判空(null)查询)
[4. order by 排序查询](#4. order by 排序查询)
[4.1 升序排序(默认)](#4.1 升序排序(默认))
[4.2 降序排序](#4.2 降序排序)
[4.3 组合排序](#4.3 组合排序)
[4.4 对表达式进行排序、使用列的别名排序](#4.4 对表达式进行排序、使用列的别名排序)
[5. limit 分页查询](#5. limit 分页查询)
[5.1 语法](#5.1 语法)
[5.2 示例](#5.2 示例)
[6. 补充:各种子句的执行时机问题](#6. 补充:各种子句的执行时机问题)
[6.1 SQL子句的实际执行顺序](#6.1 SQL子句的实际执行顺序)
[6.2 哪些子句可以起别名](#6.2 哪些子句可以起别名)
[6.3 不同执行顺序的子句如何引用别名](#6.3 不同执行顺序的子句如何引用别名)
1. insert 新增
语法:
insert [ into ] 表名 [ (字段1 [, 字段2] ...) ] values (第一行数据) [ ,(第二行数据) ];
解释:
- 紫色文字是关键字,方括号[ ]表示可选项。
- 全列查询时,表名右侧不需要字段列表;如果要指定列查询 ,则字段列表必须用**小括号()**括起来。
- values关键字右侧至少要有一行数据 ,数据内容用小括号() 括起来。如果要插入多条数据 则用逗号隔开。
1.0 前期准备
创建⼀个⽤于演示的表:
sql
drop table if EXISTS users;
create table users (
id bigint,
name varchar(20) comment '用户名'
);
1.1 全列插入
注意事项:
全列查询时,行数据中的值 的数量和顺序必须与定义表的列 的数量及顺序保持一致。
例如:定义表时,从左往后的列分别是'id'、'name',所以我们全列插入时也要按照这个顺序。
sql
# 使用全列插入的方式插入一条记录:
insert into users values(1, '张三');
插入结果:

1.2 指定列插入
注意事项:
全列查询时,行数据中的值的数量和顺序必须与指定的列的数量及顺序保持⼀致。
例如:
sql
#指定插入顺序:name -> id
INSERT INTO users (name, id) VALUES ('李四', 2);
#指定只插入部分列:name
INSERT into users (name) VALUES ('王五');

指定插入的顺序是values右侧++小括号内部数据的排列顺序++ ,而插入成功后还是以定义表的顺序排列。
指定部分列的插入后,没被指定的列的值用null填充。
1.3 同时插入多行数据
注意事项:
每个小括号表示一行数据,每行数据之间用逗号隔开。
例如:
sql
-- 多行数据的插入
INSERT INTO users (id, name) VALUES (4, '小四'), (5, '小五'), (6, '小六');

2. select 查询
语法:
SELECT
[ DISTINCT ] 列1 [,列2] ... [,列n]
[FROM 表名]
[WHERE 指定条件]
[ORDER BY {列名 | 表达式 } [ASC | DESC], ... ]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[GROUP BY {col_name | expr}, ...]
[HAVING where_condition]
- 本篇文章只讲解where、order by 和 limit 关键字,group by 和 having关键字请关注下一篇文章《》。
在SQL语法中,select 关键字类似我们 Java 中 System.out.println() 方法,它的作用就是显示查询结果。
例如:打印3 + 3的结果。

2.0 示例的数据准备
构造数据:
sql
# 新增一个表来提供查询语句的测试
CREATE TABLE exam (
id BIGINT,
name VARCHAR(20) COMMENT '同学姓名',
chinese float COMMENT '语文成绩',
math float COMMENT '数学成绩',
english float COMMENT '英语成绩'
);
# 插入测试数据
INSERT INTO exam (id, name, chinese, math, english) VALUES
(1, '唐三藏', 67, 98, 56),
(2, '孙悟空', 87, 78, 77),
(3, '猪悟能', 88, 98, 90),
(4, '曹孟德', 82, 84, 67),
(5, '刘玄德', 55, 85, 45),
(6, '孙权', 70, 73, 78),
(7, '宋公明', 75, 65, 30);
2.1 基础查询
常见格式:
select 查询列表 from 表名;
- 查询列表中可以是列,可以是表达式,也可以是通配符。列和列(表达式、通配符)之间用逗号隔开。
1. 全列查询
使用通配符*****可以查询表中所有列的值。
示例: select * from exam;

通配符 * 可以与表达式或列同时存在:select *, 11 from exam;

2. 指定列查询
例如:
sql
-- 指定部分列
select name from exam;
-- 指定查询列的顺序
SELECT name, id from exam;


3. 表达式的查询
-- 1.常量表达式
mysql> SELECT id,name, 111.11, '查看详情' FROM exam;
结果:
+------+--------+--------+----------+
| id | name | 111.11 | 查看详情 |
+------+--------+--------+----------+
| 1 | 唐三藏 | 111.11 | 查看详情 |
| 2 | 孙悟空 | 111.11 | 查看详情 |
| 3 | 猪悟能 | 111.11 | 查看详情 |
| 4 | 曹孟德 | 111.11 | 查看详情 |
| 5 | 刘玄德 | 111.11 | 查看详情 |
| 6 | 孙权 | 111.11 | 查看详情 |
| 7 | 宋公明 | 111.11 | 查看详情 |
| 8 | 张飞 | 111.11 | 查看详情 |
+------+--------+--------+----------+
8 rows in set (0.01 sec)
-- 2.把所有学⽣的语⽂成绩加10分(普通表达式)
sql
SELECT id, Name, CHINESE + 10 FROM exam; --使用默认字符集时,不区分大小写

4. 字段的别名
语法:
select 字段1 [as] '别名1',字段2 [as] 别名2,... from 表名;
- 字段只包括 列 和 表达式,不包括通配符 *。
- 使用AS关键字可以给字段起上别名。
- 别名可以用 单引号' ' 括起来,也可以省略单引号。AS关键词也可以省略,字段与别名用空格隔开。
- 注意:如果既没有单引号,也没有AS的指定,此时别名内部不能有空格。
-- 计算所有学⽣语⽂、数学和英语成绩的总分
sql
SELECT id, name, chinese + math + english FROM exam;

通过 表达式chinese+math+english 我们可以计算出3个科目的总分,但是这条表达式太长了,看起来不美观。此时我们可以给它起个别名:
sql
-- 给字段起别名(as)
SELECT id, name, chinese+math+english as '总分' FROM exam;
SELECT id, name, chinese+math+english as 总分 FROM exam; #别名内部无空格则可以省略单引号
SELECT id, name, chinese+math+english 总分 FROM exam; #同时也能省略as,只需要一个空格隔开
结果都相同,显示时字段chinese+math+english都变成了"总分":

5. 结果去重查询
格式:
select distinct 查询列表 from 表名;
- 在查询列表前面 加上distinct关键字即可去重。
- 去重判断的依据 与 查询列表中字段的数量有关。
-- 1.1 查询当前所有人的数学成绩(不去重)
sql
SELECT math FROM exam;

此时返回的结果有8条记录,其中分数98重复了
-- 1.2 查询当前所有人的数学成绩(去重)
sql
SELECT distinct math FROM exam;

去重后只有7条记录。
如果是多个列去重,那么必须是++所有指定列的数据都重复++才会去掉该行数据
-- 示例
sql
SELECT math, id FROM exam;
SELECT DISTINCT math, id FROM exam; #此时的去重判断不是只看math列
因为去重的依据是 math 与 id 的组合,两者的结果都一样:

3. where 查询
常见格式:
select 查询列表 from 表名 where 条件判断;
在where子句中会用到条件判断,而条件判断离不开比较运算和逻辑运算。
3.1 mysql的比较运算、逻辑运算
比较运算:
|-----------------------------|-----------------------------------------------------|
| 运算符 | 说明 |
| >, >=, <, <= | ⼤于,⼤于等于,小于,小于等于 |
| = | 等于,该等于对于NULL的⽐较不安全,⽐如NULL=NULL结果还是NULL |
| <=> | 等于,对于NULL的⽐较是安全的,⽐如NULL<=>NULL结果是1(true) |
| !=, <> | 不等于,对于NULL的比较都是不安全的。 |
| 字段 BETWEEN a AND b | 范围匹配 [a, b],如果a <= 数值 <= b,返回1(true) |
| 字段 NOT BETWEEN a AND b | 范围匹配 ( -∞, a)U(b, +∞),如果a <= 数值 <= b,返回 0 (false) |
| 字段 IN (option, ...) | 如果字段的值在optoin列表中,则返回1(true) |
| 字段 NOT IN (option, ...) | 如果字段的值在optoin列表中,则返回0(false) |
| 字段 IS NULL | 值为null时返回1(true) |
| 字段 IS NOT NULL | 值为null时返回0(false) |
| LIKE | 模糊匹配,%表⽰任意多个(包括0个)字符;_表⽰任意⼀个字符,NOT LIKE则取反 |
注意事项:
- MySQL语法中没有双等于号 ==, = 就能够表示等于。
- 在SET子句中 = 是赋值运算符。例如:UPDATE users SET name = 'John' WHERE id = 1;
- <=>对于null的比较是安全的,而<>对于null的比较并不安全。
- 任何非安全的比较符,使用它与null的比较结果都为null,而不是0(false)。这是因为SQL语法中采用的是三值比较(true, false, null),而不是传统的二值比较(true, false)。
示例:

如果要表示3不为null,可以使用 3 IS NOT null ,或者使用NOT (3 <=> null)。

3.2 比较查询
对于where查询来说,我们可以分为两步:
- 确定查询的条件
- 确定要查询哪些列
-- 1.查询英语不及格的同学及英语成绩(分数<60为不合格):单列的比较
sql
SELECT name, english FROM exam WHERE english < 60;

-- 2.查询语文成绩大于英语成绩的同学:列与列之间的比较
sql
SELECT name, chinese, english FROM exam where chinese > english;

-- 3.总分在230分以下的同学:表达式的比较
sql
SELECT name 姓名, chinese + math + english 总分 FROM exam
WHERE chinese + math + english < 230;

3.3 模糊查询
like子句注意事项:
- 模糊查询通常只用于字符串类型的匹配。
- 通配符 % :匹配任意长度个(包括0个)字符。
- 占位符 _ :匹配1个字符。
例如:
sql
SELECT * FROM exam WHERE name like '孙%'; #匹配任意数量个字符
SELECT * FROM exam WHERE name like '孙_'; #匹配一个字符
SELECT * FROM exam WHERE name like '孙__'; #匹配两个字符
SELECT * FROM exam WHERE name like '孙___'; #匹配三个字符
'孙%' 找到的是所有以"孙"开头的字符串:

'孙_' 表示**"孙某"** ,'孙_ _'表示 "孙某某",以此类推:



3.4 区间(范围)查询
-- 1.查询语文成绩大于80分,且英语成绩大于80分的同学
sql
SELECT name, chinese, english FROM exam WHERE chinese > 80 AND english > 80;

-- 2.查询语文成绩大于80 或 英语成绩大于80分的同字
sql
SELECT name, chinese, english FROM exam WHERE chinese > 80 OR english > 80;

-- 3.语文成绩在[80,90]分的同学及语文成绩
这里有两种实现方式,一种是用and连接两个比较运算,一种是使用between and语句:
sql
SELECT NAME, chinese FROM exam WHERE chinese >= 80 and chinese <= 90;
SELECT NAME, chinese FROM exam WHERE chinese between 80 and 90;
两者结果都一样:

-- 4.数学成绩是 78 或者 79 或者 98 或者 99 分的同学及数学成绩
使用多个 or 连接多个比较运算会看起来很臃肿,我们可以使用 in 关键字来简化语句:
sql
SELECT NAME, math FROM exam WHERE math in(78, 79, 98, 99);

3.5 判空(null)查询
注意事项:除了使用 <=> 安全比较符,NULL与任何值的运算结果都为NULL。
例如: SELECT 10 + null;

构造数据
目前exam表中还没有一列数据的值是null的:
现在我们插入一行含null值的数据,以方便我们后续的试验和讲解:
sqlinsert into exam values(8, '张飞', 27, 0, NULL);
-- 1. 查询英语成绩为NULL的记录
我们先查一下目前有的数据是否包含 张飞 同学:

此时我们把值为null的数据剔除掉,那么 张飞 同学的数据就不会在结果集中:
sql
select name, chinese + math + english from exam
WHERE english IS NOT NULL;

4. order by 排序查询
常见格式:
SELECT 查询列表 FROM 表名 [ where子句 ] ORDER BY {列名 | 表达式 } [ ASC | DESC ];
- ASC 表示升序排序。
- DESC 表示降序排序。
- 排序选项为空时则默认使用升序排序。
- 在排序时,SQL语法会把 NULL值 排在比最小值还要小的位置,也就是说升序数null值在第一行数据,降序时null值在最后一行数据。(注意:这不能意味着null值比任何值都小,因为 null <= 值、null >= 值 的比较结果都是null,null在SQL中表示的意思是未知值、未知)。
4.1 升序排序(默认)
-- 按数学成绩从低到高排序 (升序)
sql
SELECT * FROM exam ORDER BY math;
SELECT * FROM exam ORDER BY math ASC;


4.2 降序排序
-- 按英语成绩从高到低排序 (降序)
sql
SELECT * FROM exam ORDER BY english DESC;

4.3 组合排序
- 各排序规则用逗号隔开。
- 排序规则的优先级是从左往右逐渐变小。(后面的排序 是在 前面的结果 进行的)
-- 查询同学各门成绩,依次按数学降序,英语升序,语文升序的方式显示
sql
SELECT * FROM exam ORDER BY math DESC, english ASC, chinese ASC;

4.4 对表达式进行排序、使用列的别名排序
-- 1.查询同学及总分,由高到低排序
sql
select name, chinese + math + english from exam
order by chinese + math + english desc;

这里张飞的总分为null的原因是他的english分数为null,任何值加上null都为null。
-- 2.表达式太长了,我们可以使用它的别名来排序:
sql
select name, chinese + math + english as 总分
from exam order by 总分 desc;

5. limit 分页查询
5.1 语法
1. SELECT ... FROM 表名 [ where子句 ] [ order by子句 ] LIMIT num;
2. SELECT ... FROM 表名 [ where子句 ] [ order by子句 ] LIMIT start,num;
3. SELECT ... FROM 表名 [ where子句 ] [ order by子句 ] LIMIT num OFFSET start;
- start 表示起始的行下标,num 表示筛选数据的总行数。
- 第一条语句中省略了start ,那么它的默认初始行下标为 0。
- 第二条 与 第三条语句表示的意义相同,offset的意思是表示从哪开始索引。
- 返回的数据其行下标为[start,start + num - 1]。如果超出了表数据中的最大行下标,那么超出的部分返回是空的(是empty,不是null值)。
5.2 示例
-- 1.筛选出exam表中的前3条数据:
sql
SELECT * FROM exam limit 3;
SELECT * FROM exam limit 0,3;
SELECT * FROM exam limit 3 offset 0;
三者结果相同:

-- 2.倒序排序后,再筛选出前3条数据:
sql
SELECT * FROM exam ORDER BY id DESC limit 3;

-- 3. 超出范围会返回一个空:(exam表总共8条数据)
sql
SELECT * FROM exam limit 6,4;
搜索范围,索引:[6, 9]、id值:[7, 10]。返回的只有id为7和8的数据:

sql
SELECT * FROM exam limit 9,4;
搜索范围,索引:[9, 12]、id值:[10, 13]。返回的是一个空。

6. 补充:各种子句的执行时机问题
6.1 SQL子句的实际执行顺序
SQL查询的实际执行顺序与书写顺序不同,理解这一点对别名使用至关重要:
-- 书写顺序 SELECT column_alias, expression FROM table WHERE condition ORDER BY column LIMIT count; -- 实际执行顺序 1. FROM -- 确定数据源 2. WHERE -- 过滤行数据 3. SELECT -- 选择列并计算表达式 4. ORDER BY -- 排序结果 5. LIMIT -- 限制结果数量
在select之前执行的操作(from、where)都是在真实表上操作,在select之后执行的操作(order by、limit)都是在虚拟表上操作。
数据准备阶段:处理基础表数据。
结果构建阶段(SELECT):构建包含计算列和别名的结果集(虚拟表)。
结果处理阶段:对最终结果集进行排序和限制。
6.2 哪些子句可以起别名
这么多种子句,只有select子句和from子句可以起别名。
SELECT子句**:** 定义列别名。
FROM子句**:** 定义表别名。
其他子句不能定义别名。
定义好表别名后,可以通过**" 表别名.列 "**的方式使用表中的列。
常量表达式也是可以起别名,它属于列别名:
sql
SELECT 10 ten FROM exam;

6.3 不同执行顺序的子句如何引用别名
规则:执行顺序上,排在后面的子句可以使用前排子句起的别名。
详情:
- FROM → 可定义表别名
- WHERE → 可引用表别名,不能引用列别名
- SELECT → 可定义列别名,可引用表别名
- ORDER BY → 可引用表别名和列别名
- LIMIT → 不能引用任何别名(特殊)
正例:各子句使用表别名
sql
SELECT ex.name, ex.math FROM exam AS ex
WHERE math < 80 ORDER BY ex.english;

反例:
-- where不能起别名
SELECT * FROM exam where (math as 数学) < 80;
-- where不能使用select中的别名
SELECT id, name, math 数学 FROM exam where 数学 < 80;
本期分享完毕,感谢大家的支持Thanks♪(・ω・)ノ



