# DML 语句

# 什么是 DML?

DML:Data Manipulation language

用来操作存储在数据中的数据,常用的 DML 语句有:

  • 新增表中的数据:insert into
  • 删除表中的数据:delete
  • 修改表中的数据:update
  • 查询表中的数据:select

官网 DML 文档地址

# insert 语句

语法如下

 INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    [PARTITION (partition_name [, partition_name] ...)]
    [(col_name [, col_name] ...)] 		-- 列清单
    {VALUES | VALUE} (value_list) [, (value_list)] ...	-- 值清单
    [ON DUPLICATE KEY UPDATE assignment_list] -- 当出现主键或唯一索引冲突事件的行为,比如更新旧数据

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    [PARTITION (partition_name [, partition_name] ...)]
    SET assignment_list
    [ON DUPLICATE KEY UPDATE assignment_list]

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    [PARTITION (partition_name [, partition_name] ...)]
    [(col_name [, col_name] ...)]
    SELECT ...
    [ON DUPLICATE KEY UPDATE assignment_list]

value:
    {expr | DEFAULT}

value_list:
    value [, value] ...

assignment:
    col_name = value

assignment_list:
    assignment [, assignment] ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 编写 Insert 语句的思路

  • 确认要把数据插入到哪个表中?

  • 确认表的数据库结构,哪些列不能为 NULL,对于不能为 NULL 的列是否有默认值

    -- 可以通过命令语句查看表结构
    mysql> SHOW CREATE TABLE imc_db.imc_class \G;
    *************************** 1. row ***************************
           Table: imc_class
    Create Table: CREATE TABLE `imc_class` (
      `class_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT COMMENT '课程分类ID',
      `class_name` varchar(10) NOT NULL DEFAULT '' COMMENT '分类名称',
      `add_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间',
      PRIMARY KEY (`class_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='课程分类表'
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
  • 确认对应插入列的插入值的清单

# insert 语句示例

比如下面就指定了一列名称,并往课程分类表中插入了多条数据

INSERT INTO imc_class ( class_name )
VALUES
	( 'MySQL' ),
	( 'REDIS' ),
	( 'MongoDB' ),
	( '安全测试' ),
	( 'Oracle' ),
	( 'SQL Server' ),
	( 'Hbase' );
1
2
3
4
5
6
7
8
9

在创建表的时候,没有为 class_name 添加唯一索引,这里使用上节提到的创建索引语句来增加

CREATE UNIQUE
	INDEX uqx_classname ON imc_class ( class_name );
-- 创建 union 的索引,并取名为 uqx_classname ,在 imc_class 的 class_name 列上创建
1
2
3

唯一索引创建好之后,再执行上述的插入语句就会出现以下的提示错误信息

1062 - Duplicate entry 'MySQL' for key 'uqx_classname', Time: 0.001000s
1

# ON DUPLICATE KEY UPDATE 示例

由于添加了唯一索引,插入失败,这个时候可以使用 ON DUPLICATE 语句吧 add_time 列的数据修改

INSERT INTO imc_class ( class_name )
VALUES
	( 'MySQL' ) 
	ON DUPLICATE KEY UPDATE add_time = CURRENT_TIME;

-- 响应结果是 2 行记录受到了影响,是因为:先删除 MySQL 的值,再更新我们的值
Affected rows: 2, Time: 0.002000s
1
2
3
4
5
6
7

# select 语句

在 DML 中完成查询的语句是 select 语句,使用很频繁,且为复杂的一个知识点

SELECT  -- SELECT 是唯一必选的
    [ALL | DISTINCT | DISTINCTROW ]
      [HIGH_PRIORITY]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      SQL_NO_CACHE [SQL_CALC_FOUND_ROWS]
    select_expr [, select_expr ...] -- 列或表达式
    [FROM table_references
      [PARTITION partition_list]
    [WHERE where_condition]
    [GROUP BY {col_name | expr | position}, ... [WITH ROLLUP]]
    [HAVING where_condition]
    [WINDOW window_name AS (window_spec)
        [, window_name AS (window_spec)] ...]
    [ORDER BY {col_name | expr | position}
      [ASC | DESC], ... [WITH ROLLUP]]
    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
    [INTO OUTFILE 'file_name'
        [CHARACTER SET charset_name]
        export_options
      | INTO DUMPFILE 'file_name'
      | INTO var_name [, var_name]]
    [FOR {UPDATE | SHARE} [OF tbl_name [, tbl_name] ...] [NOWAIT | SKIP LOCKED] 
      | LOCK IN SHARE MODE]]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
-- 列或表达式是说:下面这样直接写值,还有一个表达式,就可以执行查询
-- 在该语句下,select 从句就如同打印语句的功能
SELECT 'hello','MySql', 2018+1

查询结果如下:
列:hello	MySql	2018+1
值:hello	MySql	2019
1
2
3
4
5
6
7

# where 语句

查询出所有课程中包含 MYSQL 的课程的课程名称

SELECT
	title 
FROM
	imc_db.imc_course 
WHERE
	title LIKE '%mysql%'
1
2
3
4
5
6

# 编写简单查询语句的思路

  • 确定 FROM 子句:首先确定我们要获取的数据存在哪些表中
  • 确定 SELECT 子句:其次是确定我们要取现表中的哪些列
  • 确定 WHERE 子句:确认是否需要对表中的数据进行过滤

下面是着重对 select 中能使用的一些知识进行讲解

# MySQL 的比较运算符

  • = > < >= <= <> !+<> 和 -= 都表示不等于

  • BETWEEN min AND max:列值大于等于最小值,小于等于最大值

  • IS NULLIS NOT NULL:判断列的值是否为 null

  • LIKENOT LIKE% 代表任何数量的字符,_ 代表任何一个字符

  • INNOT IN:判断列的值是否在指定的值列表中

-- 列中是否包含 mysql 关键词
SELECT 'this is mysql course' LIKE '%mysql%';

-- 下划线的用法,这条语句是能查询到的
SELECT 'Mysql' LIKE '_ysql'; 

-- 如果是这样就不行了,因为只表示任意 一个字符匹配。 前面有好几个字符
SELECT 'xxxMysql' LIKE '_ysql'; 
1
2
3
4
5
6
7
8

# 本项目数据库结构和模拟数据

这里提供了所有的项目表和结构和数据备份文件,删除前面创建的表,这里执行下,就可以进行后续的练习使用了

请前往 GitHub 下载该文件

# MySQL 的逻辑运算符

  • AND、&&: AND 运算符两边的表达式都为真,返回的结果才为真
  • OR、||:OR 运算符两边的表达式有一条为真,返回结果就为真
  • XOR:一真一假时返回真

TIP

任何运算符和 NULL 值运算结果都为 NULL,所以我们之前在定义表的时候,都定位为了非空

-- 需求:  查询出课程标题中包含 MySQL 关键词并且学习人数小于 5000,
--  			课程标题中不包含 MySQL 关键词但学习人数大于 5000 的课程
--  			显示:课程标题和学习人数

-- 方法 1: 编写两条语句,然后使用 UNION ALL 组合起来
SELECT
	title,
	study_cnt 
FROM
	imc_db.imc_course 
WHERE
	title LIKE '%MySQL%' 
	AND study_cnt < 5000 UNION ALL SELECT title, study_cnt FROM imc_db.imc_course WHERE title NOT LIKE '%MySQL%' AND study_cnt > 5000
	
-- 方法 2:使用 异或 XOR
SELECT
	title,
	study_cnt 
FROM
	imc_db.imc_course 
WHERE
	title LIKE '%MySQL%' 
	XOR study_cnt > 5000 
-- 别懵逼,记住 一真一假 为真:
-- 也就是说:要么这一条记录 「包含 MySQL 但是学习人数 小于 5000」
-- 				 要么这一条记录「不包含 MySQL 但是学习人数 大于 500」
-- 这个描述就刚好符合我们的需求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 从多个表中获取数据 join

前面查询都是单表查询,如何从多表中查询呢? 表与表之间要存在一定的关联关系

如下 3 张表,他们的关系就是都有课程 ID,在逻辑上来说,课程有多个章节,章节有多个小节,这就是关系

课程表:课程 ID
课程章节表:课程 ID
课程小节表:课程 ID、章节 ID
1
2
3

使用 JOIN 关键字来关联两张表,又分为:

  • INNER JOIN 内连接:两张表的交集

  • OUTER JOIN 外连接:又细分为两个

    • LEFT JOIN 左外连接:

      并集:以左边表为主,即使右边变没有匹配的数据,左边的数据都会出来;

      补集:还可以通过加 WHERE 子句(判断 B 表中必有值的数据为 null),查询只存在 A 表中,而不存在 B 表中的数据,如下面的练习,查询没有任何章节的课程

    • RIGHT JOIN 右外连接:与左外链接相反

-- 内连接练习:查询每一门课程的 课程 ID、课程名称和章节名称
SELECT
	a.course_id,
	a.title,
	b.chapter_name 
FROM
	imc_course a
	JOIN imc_chapter b ON b.course_id = a.course_id
-- 使用 join 关联两个表,使用 ON 来声明两个表中的关联关系

-- 新增一条课程数据
INSERT INTO `imc_db`.`imc_course`(`title`, `title_desc`, `type_id`, `class_id`, `level_id`, `online_time`, `study_cnt`, `course_time`, `intro`, `info`, `harvest`, `user_id`, `main_pic`, `content_score`, `level_score`, `logic_score`, `score`) VALUES ('关联测试', '关联测试', 10, 5, 1, '2020-04-20 07:26:23', 0, '00:00:00', '', '', '', 0, '', 0.0, 0.0, 0.0, 0.0);

-- 使用上面的内连接查询新插入的数据,会发现没有结果出来
SELECT
	a.course_id,
	a.title,
	b.chapter_name 
FROM
	imc_course a
	JOIN imc_chapter b ON b.course_id = a.course_id
	WHERE a.title = '关联测试'
	
-- 	可以使用外链接来查询到,即使该课程没有任何章节
SELECT
	a.course_id,
	a.title,
	b.chapter_name 
FROM
	imc_course a
	LEFT JOIN imc_chapter b ON b.course_id = a.course_id
	WHERE a.title = '关联测试'
	
-- 左外连接还有一个查询技巧:就是查询没有任何章节的课程
-- 上面演示的 SQL 由于我知道这条数据没有章节,如果去掉就会显示还包含有章节的课程了
-- 这里只要加上 where 条件,判定章节中的必有字段为 null 即可
SELECT
	a.course_id,
	a.title,
	b.chapter_name 
FROM
	imc_course a
	LEFT JOIN imc_chapter b ON b.course_id = a.course_id
	WHERE b.course_id IS NULL
-- 响应的结果
course_id	| title |	chapter_name
101				|	关联测试 |  null
-- 此种方式,比使用 not in(子查询) 来达成,性能要好
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# group by 、having 分组语句

GROUP BY...HAVING 子句的作用:

  • 把结果集按某些列分成不同的组,并对分组后的数据进行聚合操作
  • 可以通过 having 对分组后的数据进行过滤,where 语句只能用在分组前
--范例 1: 查询每个难度的课程有多少门课程
SELECT
	b.level_name,  -- 分组键可以出现在 select 语句中,非分组键则不能
	count( * )  -- 还可以包含一个或多个聚合函数
FROM
	imc_course a
	JOIN imc_level b ON a.level_id = b.level_id 
GROUP BY
	b.level_name 
	
-- 查询响应数据	
level_name	count( * )
入门	22
初级	28
高级	24
中级	27

-- 如果非分组列出现在了 select 中则会出现  sql_mode=only_full_group_by 类似的错误信息
-- 这是因为 group by 的使用时受 sql_mode 的影响,可以查看当前的 sql_mode 值
SHOW VARIABLES  LIKE 'sql_mode'

-- 从响应的数据中可以看到:的确有 ONLY_FULL_GROUP_BY 的配置
Variable_name	Value
sql_mode	ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

对分组后的语句进行过滤

-- 统计每个分类下课程大于 3 门的难度有哪些
SELECT
	b.class_name,
	c.level_name,
	count( * ) 
FROM
	imc_course a
	JOIN imc_class b ON b.class_id = a.class_id
	JOIN imc_level c ON c.level_id = a.level_id 
GROUP BY
	b.class_name,
	c.level_name 
HAVING
	count( * ) > 3   -- 在分组后,进行过滤

-- 响应数据
class_name	level_name	count( * )
Hbase	初级	4
Oracle	初级	4
Hbase	高级	5
运维	高级	4
MySQL	高级	4
Redis	初级	4
MongoDB	入门	4
HadoopDock	中级	4
Docker	中级	4
运维	中级	4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 常用的聚合函数

  • count(*)count(col):统计函数

    * 表示的这一行数据,也可以选择具体的列,因为有些列有值或则没有值,和具体的聚合函数的用途有关

  • sum(col_name):累加函数

    计算表中符合条件的数值列的合计值,此列需要是数值类型

  • avg(cole_name):平均

    计算表中符合条件的数值列的平均值(就是 sum/count)

  • MAX(cole_name):计算表中符合条件的任意列中数据的最大值

  • MIN(cole_name):计算表中符合条件的任意列中数据的最小值

# count 统计范例

-- 统计函数 范例:统计课程表的总课程数量 与 课程中老师的数量
SELECT
	count( course_id ),  -- 统计课程 ID,就是课程数量
	count( DISTINCT user_id ) -- 统计该课程老师数量,因为一个老师可以负责多个课程,需要去重
FROM
	imc_course
	
-- 响应数据
count( course_id )	count( DISTINCT user_id )
101	6
1
2
3
4
5
6
7
8
9
10

# avg 范例

-- 一个复杂点的 sql:利用课程评价表中的评分,更新课程表中的课程的评分
-- 课程评价表中的数据是每个用户对课程的评分
-- 课程表中的评分是需要 课程评价表中的评分的平均值,作为一个综合评分

对于复杂的语句,我们需要分段来写 sql,先实现一段,再继续另一端,再合并起来,这里还没有学习更新语句,后半段就先留着后续来补充

-- 查询:统计每门课程的平均分
SELECT
	course_id,
	avg( content_score ) AS content_score,
	avg( level_score ) AS level_score,
	avg( logic_score ) AS logic_score,
	avg( score ) AS avg_score 
FROM
	imc_classvalue 
GROUP BY
	course_id
	
-- 响应数据
course_id	content_score	level_score	logic_score	avg_score
8	8.98000	9.14000	8.58000	0.00000
17	9.10000	9.10000	9.45000	0.00000
59	8.85000	8.90000	8.82500	0.00000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# max 范例

-- 查询出学习人数最多的课程
SELECT
	title 
FROM
	imc_course 
WHERE
	study_cnt = ( SELECT MAX( study_cnt ) FROM imc_course )
-- 需要分两步查询出来
-- 第一步:先查询出来人数最多的列,就是这个字查询,会显示出人数
-- 第二步:以该人数为条件,查询出对应的课程信息
1
2
3
4
5
6
7
8
9
10

# order by 排序

每个存储引擎默认的排序方式是不同的,InnoDB 默认是使用主键的顺序进行排序。那么使用 order by 子句是对查询结果进行排序的最安全的方法。

  • 列名后增加 ASC 升序排列,DESC 降序排列

    如 order by id desc

  • order by 子句也可以使用 select 子句中未出现的 或是 函数

-- 查询出每门课程的学习人数,并按学习人数从高到底排列
SELECT
	title,
	study_cnt 
FROM
	imc_course 
ORDER BY
	study_cnt DESC
	-- ORDER BY 2 DESC 还可以使用 slect 列 的位置来引用排序
	
-- 响应数据
title	study_cnt
PostgreSQL课程-64209	9939
SQLServer课程-68633	9731
MySQL课程-86475	9716
PostgreSQL课程-33460	9588
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# Limit 限制返回结果集行数

常用语数据列表分页,一定要和 order by 子句配合使用,是因为:由于分页过程中每次分页查询都会重复的执行查询语句,所以要保证排序顺序是一样的,否则就可能出现错误的数据

语法:limit 起始偏移量,结果集的行数

SELECT
	course_id,
	title
FROM
	imc_course 
ORDER BY study_cnt DESC
LIMIT 0,10  -- 起始数据从 0 开始,返回 10 行数据
						-- 如果是第 2 页的数据,则是 limit 10,10
1
2
3
4
5
6
7
8

# 创建视图 create view

视图中不存储数据

CREATE
    [OR REPLACE]
    [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
    [DEFINER = user]
    [SQL SECURITY { DEFINER | INVOKER }]
    VIEW view_name [(column_list)]
    AS select_statement  -- 我们熟悉的查询语句
    [WITH [CASCADED | LOCAL] CHECK OPTION]
1
2
3
4
5
6
7
8
-- 定义一个包含课程 ID、课程名称、课程分类、课程方向以及课程难度的视图
-- 第一步:先写出这些数据的查询语句
SELECT
	a.course_id,
	a.title,
	b.class_name,
	c.type_name,
	d.level_name 
FROM
	imc_course a
	JOIN imc_class b ON b.class_id = a.class_id
	JOIN imc_type c ON c.type_id = a.type_id
	JOIN imc_level d ON d.level_id = a.level_id
-- 响应数据
course_id	title	class_name	type_name	level_name
1	MySQL课程-79889	大数据	算法&数学	入门
2	MySQL课程-69546	Hbase	云计算&大数据	初级
3	PostgreSQL课程-43917	大数据	前端开发	高级
...

-- 定义视图,取名 vm_course
CREATE VIEW vm_course AS 
SELECT
  a.course_id,
  a.title,
  b.class_name,
  c.type_name,
  d.level_name 
FROM
	imc_course a
	JOIN imc_class b ON b.class_id = a.class_id
	JOIN imc_type c ON c.type_id = a.type_id
	JOIN imc_level d ON d.level_id = a.level_id
	
-- 查询视图
SELECT * FROM  vm_course
-- 可以看到,视图就类似一章虚拟表,把我们编写的 sql 语句保存起来了的感觉
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# delete 按条件删除数据

DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name
    [PARTITION (partition_name [, partition_name] ...)]
    [WHERE where_condition]
    [ORDER BY ...]
    [LIMIT row_count]
1
2
3
4
5

删除语法中也有 where 等语句,与 select 中的效果类似

-- 范例 1:删除课程表中没有章节信息的课程
-- 第一步:先写出没有章节信息的课程信息
SELECT
	* 
FROM
	imc_course a
	LEFT JOIN imc_chapter b ON a.course_id = b.course_id 
WHERE
	b.course_id IS NULL
	
-- 第二步:使用 delete 语法
DELETE a -- 删除哪个表中的数据,因为下面关联了两张表
FROM
	imc_course a
	LEFT JOIN imc_chapter b ON a.course_id = b.course_id 
WHERE
	b.course_id IS NULL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 范例 2:删除课程方向表中重复的课程方向,并保留方向 ID 最小的一条,并在方向名称上增加唯一索引
-- 01. 首先查看 方向表 的结构
SHOW CREATE TABLE imc_type;
-- 响应的结构
CREATE TABLE `imc_type` (
  `type_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT COMMENT '课程方向ID',
  `type_name` varchar(10) NOT NULL DEFAULT '' COMMENT '课程方向名称',
  `add_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '填加时间',
  PRIMARY KEY (`type_id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='课程方向表'
-- 可以看到 type_name 上没有唯一索引,所以会导致重复的数据进入

-- 02. 先查看下有哪些数据是重复的(注意,前面给出的数据表,里面没有重复的数据,需要自己手动新增几条)
SELECT
	type_name,
	count( * ) 
FROM
	imc_type 
GROUP BY
	type_name 
HAVING
	count( * ) > 1
	
-- 03. 找出保留 id 最小的数据
SELECT
	type_name,
	count( * ),
	min( type_id ) AS min_type_id   -- 由于分组后相同的只会出现一条数据,直接追加最小值就是正确的
FROM
	imc_type 
GROUP BY
	type_name 
HAVING
	count( * ) > 1
-- 响应的数据
type_name	count( * )	min_type_id
数据库	2	8
游戏	2	10

-- 04. 找出要删除的数据,使用子查询
SELECT
	* 
FROM
	imc_type AS a
	JOIN ( SELECT type_name, count( * ), min( type_id ) AS min_type_id FROM imc_type GROUP BY type_name HAVING count( * ) > 1 ) AS b ON a.type_name = b.type_name 
	AND a.type_id > b.min_type_id
-- 响应的数据,可以看到查询出来的都是比 min_type_id 大的数据
type_id	type_name	add_time	type_name(1)	count( * )	min_type_id
11	游戏	2020-04-20 10:39:12	游戏	2	10
12	数据库	2020-04-20 10:39:36	数据库	2	8

-- 05. 最终形成的删除数据
DELETE a 
FROM
	imc_type AS a
	JOIN ( SELECT type_name, count( * ), min( type_id ) AS min_type_id FROM imc_type GROUP BY type_name HAVING count( * ) > 1 ) AS b ON a.type_name = b.type_name 
	AND a.type_id > b.min_type_id
	
-- 06. 创建唯一索引
CREATE UNIQUE INDEX uqx_typename ON imc_type(type_name)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

# update 修改语句

UPDATE [LOW_PRIORITY] [IGNORE] table_reference
    SET assignment_list
    [WHERE where_condition]  -- 过滤出需要修改的数据
    [ORDER BY ...]
    [LIMIT row_count]

value:
    {expr | DEFAULT}

assignment:
    col_name = value

assignment_list:
    assignment [, assignment] ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14

对于 order by 和 limit 的参数一般不常用,但是可以用在大批量更新的场景:比如要更新 10 万行数据,如果一次性全部更新,可能会导致主从复制延迟的问题,所以可以采用他们来实现一定顺序的分页更新,每次只更新一万行

# 编写 update 语句的思路:

  • 确定要更新的数据存储在哪张表中?:update 子句

    通常可以先写出一个 select 语句,查找出来要修改的数据,然后再修改为 update 语句

  • 确定要更新的列与值:set 语句

  • 确认更新数据的条件:where 语句

# 常用更新语句示例

范例 1:冻结用户的账户:冻结昵称为 沙占 的用户

-- 先写查询语句
SELECT
	user_nick,
	user_status 
FROM
	imc_user 
WHERE
	user_nick = '沙占'
-- 改写成 update 语句

UPDATE imc_user 
SET user_status = 0 
WHERE
	user_nick = '沙占'
1
2
3
4
5
6
7
8
9
10
11
12
13
14

范例 2:随机推荐 10 门课程

-- 给该表新增一列,是否推荐的列,由于真实的推荐是一个很复杂的计算的出来的结果,这里简单的模拟下
-- 使用修改表的语句 alter 来新增一列
ALTER TABLE imc_course ADD is_recommand TINYINT DEFAULT 0 COMMENT '是否推荐,0 不推荐,1 推荐';

-- 随机查询出 10 条语句
SELECT
	course_id 
FROM
	imc_course 
ORDER BY RAND( )   -- 使用了 rand 函数来排序
	LIMIT 10

-- 改写成 update 语句
UPDATE imc_course 
SET is_recommand = 1 
ORDER BY
	RAND( ) 
	LIMIT 10;
	
-- 查询刚刚推荐的数据
SELECT course_id,title from imc_course WHERE is_recommand = 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

范例 3:完成 前面 svg 里面剩下的 sql 作业,更新

-- 一个复杂点的 sql:利用课程评价表中的评分,更新课程表中的课程的评分
-- 课程评价表中的数据是每个用户对课程的评分
-- 课程表中的评分是需要 课程评价表中的评分的平均值,作为一个综合评分

-- 查询:统计每门课程的平均分
SELECT
	course_id,
	avg( content_score ) AS content_score,
	avg( level_score ) AS level_score,
	avg( logic_score ) AS logic_score,
	avg( score ) AS avg_score 
FROM
	imc_classvalue 
GROUP BY
	course_id

-- 改成更新语句
UPDATE imc_course a
JOIN (
	SELECT
		course_id,
		avg( content_score ) AS content_score,
		avg( level_score ) AS level_score,
		avg( logic_score ) AS logic_score,
		avg( score ) AS avg_score 
	FROM
		imc_classvalue 
	GROUP BY
		course_id 
	) b ON a.course_id = b.course_id 
	SET a.content_score = b.content_score,
	a.level_score = b.level_score,
	a.logic_score = b.logic_score,
	a.score = avg_score
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34