融合美人鱼内购版
600.57MB · 2025-11-13
99% 的人执行 UPDATE 时忘记 WHERE 子句,导致全表数据被误改?SQL 高手却掌握 WHERE 条件、子查询更新、多表关联等技巧,数据修改精准高效。本文档用生活化比喻解析 SQL UPDATE 更新数据,从基础语法到多表关联,帮你掌握数据修改核心技能,避免数据灾难。
UPDATE(更新) 是 SQL 中用于修改表中已存在记录的语句。
生活化比喻:UPDATE 就像修改图书馆的书籍登记册(表)上已有的记录。比如某本书的借阅状态从"在馆"改为"已借出",或者更新书籍的归还日期。UPDATE 不会新增记录,只会修改现有记录的内容。
问题场景:学生表中某个学生的成绩录入错误,需要修改
不使用 UPDATE:
-- 更新学生表中 id 为 1 的学生的成绩
UPDATE students
SET score = 95
WHERE id = 1;
优势:
想象一下这样的场景:你在一家电商公司工作,负责维护用户信息表。某天,产品经理告诉你:"我们需要把所有 VIP 用户的积分增加 100 分,并且更新他们的会员等级。"
新手做法:
问题:
SQL 高手做法:
-- 一条 UPDATE 语句搞定
UPDATE users
SET points = points + 100,
level = 'VIP'
WHERE user_type = 'VIP';
优势:
通过本文档的学习,你将掌握以下核心知识点:
让我们通过一个最简单的例子来快速了解 UPDATE 语句的使用方法。
假设我们有一个学生表 students,现在需要将 id 为 1 的学生的成绩更新为 95 分。
-- 更新学生表中 id 为 1 的学生的成绩
UPDATE students
SET score = 95
WHERE id = 1;
逐行代码解释:
-- UPDATE 作用:指定要更新数据的表
UPDATE students
-- SET 作用:指定要更新的字段和新值
SET score = 95
-- WHERE 作用:指定更新条件,只更新 id 为 1 的记录
WHERE id = 1;
执行结果:
️ 重要提醒:WHERE 子句非常重要!如果省略 WHERE 子句,所有记录的 score 字段都会被更新为 95,这可能导致数据灾难!
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
语法说明:
生活化比喻:UPDATE 就像修改登记册,UPDATE table_name 是"在哪个登记册上",SET column = value 是"把哪个字段改成什么值",WHERE condition 是"只修改符合条件的记录"。
另一种语法格式(中文注释版):
UPDATE 表名称
SET 列名称 = 新值
WHERE 列名称 = 某值
| 参数 | 说明 | 是否必需 | 示例 |
|---|---|---|---|
table_name | 要修改的表名称 | 必需 | students |
column | 要修改的字段名称 | 必需 | score |
value | 要修改的新值 | 必需 | 95 |
WHERE condition | 修改条件 | ️ 强烈建议 | WHERE id = 1 |
️ 重要警告:WHERE 子句虽然不是语法上必需的,但在实际使用中强烈建议必须使用。如果省略 WHERE 子句,所有记录都将被更新!
让我们来详细学习单表更新的各种用法。单表更新是最常用的 UPDATE 操作,包括更新单条记录、多条记录等场景。
场景:更新某个学生的成绩
语法:
UPDATE table_name
SET column = value
WHERE condition;
实际例子:
-- 更新学生表中 id 为 1 的学生的成绩为 95 分
UPDATE students
SET score = 95
WHERE id = 1;
逐行代码解释:
-- UPDATE students:指定要更新 students 表
UPDATE students
-- SET score = 95:将 score 字段的值设置为 95
SET score = 95
-- WHERE id = 1:只更新 id 等于 1 的记录
WHERE id = 1;
更多示例:
-- 示例 1:更新客户表中 id 为 1 的客户的联系人和城市
UPDATE Customers
SET ContactName = 'Alfred Schmidt', City = 'Frankfurt'
WHERE CustomerID = 1;
-- 示例 2:更新人员表中姓为 'Wilson' 的人的名字
UPDATE Person
SET FirstName = 'Fred'
WHERE LastName = 'Wilson';
-- 示例 3:更新用户表中 id 为 1 的用户名
UPDATE users
SET username = '新用户名'
WHERE user_id = 1;
场景:同时更新某个学生的多个字段信息
语法:
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
实际例子:
-- 更新学生表中 id 为 2 的学生的姓名和性别
UPDATE students
SET name = 'mike', sex = '1'
WHERE id = '2';
逐行代码解释:
-- UPDATE students:指定要更新 students 表
UPDATE students
-- SET name = 'mike', sex = '1':同时更新 name 和 sex 两个字段
-- name 字段设置为 'mike',sex 字段设置为 '1'
SET name = 'mike', sex = '1'
-- WHERE id = '2':只更新 id 等于 '2' 的记录
WHERE id = '2';
更多示例:
-- 示例 1:更新人员表中姓为 'Wilson' 的人的地址和城市
UPDATE Person
SET Address = 'Zhongshan 23', City = 'Nanjing'
WHERE LastName = 'Wilson';
-- 示例 2:更新客户表中 id 为 2 的客户的多个地址字段
UPDATE client
SET rue = '49 Rue Ameline',
ville = 'Saint-Eustache-la-Forêt',
code_postal = '76210'
WHERE id = 2;
场景:批量更新符合条件的所有记录
语法:
UPDATE table_name
SET column = value
WHERE condition;
实际例子:
-- 更新所有来自 'Mexico' 的客户的联系人
UPDATE Customers
SET ContactName = 'Juan'
WHERE Country = 'Mexico';
逐行代码解释:
-- UPDATE Customers:指定要更新 Customers 表
UPDATE Customers
-- SET ContactName = 'Juan':将所有符合条件的记录的 ContactName 设置为 'Juan'
SET ContactName = 'Juan'
-- WHERE Country = 'Mexico':只更新 Country 等于 'Mexico' 的记录
-- 注意:这里可能有多条记录符合条件,都会被更新
WHERE Country = 'Mexico';
更多示例:
-- 示例 1:更新 id 在 5 到 7 之间的学生的姓名和成绩
UPDATE students
SET name = '小牛', score = 77
WHERE id >= 5 AND id <= 7;
-- 示例 2:将所有价格低于 100 的商品价格提高 10%
UPDATE products
SET price = price * 1.1
WHERE price < 100;
-- 示例 3:将所有成绩低于 80 的学生的成绩加 10 分
UPDATE students
SET score = score + 10
WHERE score < 80;
️ 严重警告:如果不加 WHERE 条件,则所有记录都会被更新!这是一个非常危险的操作!
错误示例:
-- 危险!这会更新表中所有记录的 ContactName
UPDATE Customers
SET ContactName = 'Juan';
执行结果:表中所有记录的 ContactName 字段都会被更新为 'Juan',这通常不是我们想要的结果!
另一个错误示例:
-- 危险!这会更新表中所有记录的 pays 字段
UPDATE client
SET pays = 'FRANCE';
执行结果:表中所有记录的 pays 字段都会被更新为 'FRANCE'。
正确做法:
sql_safe_updates = 1 来强制要求 WHERE 条件MySQL 安全模式设置:
-- 开启安全更新模式,强制要求 WHERE 条件
SET sql_safe_updates = 1;
开启后,如果执行没有 WHERE 条件的 UPDATE 语句,MySQL 会报错,从而避免误操作。
在 UPDATE 语句中,更新字段时可以使用表达式进行计算。
场景:给所有成绩低于 80 的学生的成绩加 10 分
语法:
UPDATE table_name
SET column = expression
WHERE condition;
实际例子:
-- 将所有成绩低于 80 的学生的成绩加 10 分
UPDATE students
SET score = score + 10
WHERE score < 80;
逐行代码解释:
-- UPDATE students:指定要更新 students 表
UPDATE students
-- SET score = score + 10:将当前行的 score 字段的值加上 10
-- 注意:这里使用了表达式 score + 10,而不是直接赋值
SET score = score + 10
-- WHERE score < 80:只更新成绩低于 80 的记录
WHERE score < 80;
表达式说明:
score + 10 是一个表达式,表示将当前记录的 score 值加上 10+、-、*、/ 等运算符更多示例:
-- 示例 1:将所有价格低于 100 的商品价格提高 10%
UPDATE products
SET price = price * 1.1
WHERE price < 100;
-- 示例 2:给所有用户的积分增加 10 分(无条件,更新所有记录)
UPDATE users
SET points = points + 10;
️ 注意事项:
UPDATE 语句可以与子查询结合使用,根据其他表的数据来更新当前表。这是 UPDATE 的高级用法之一。
场景:根据部门表更新员工表的部门名称
语法:
UPDATE table1
SET column1 = (SELECT column FROM table2 [WHERE condition])
WHERE table1.column2 = value;
实际例子:
-- 根据部门表更新员工表的部门名称
UPDATE emp e
SET e.dname = (SELECT d.dname FROM dept d WHERE e.deptno = d.deptno);
逐行代码解释:
-- UPDATE emp e:指定要更新 emp 表,使用别名 e
UPDATE emp e
-- SET e.dname = (子查询):将 dname 字段设置为子查询的结果
-- 子查询:从 dept 表中查询与当前员工部门编号匹配的部门名称
SET e.dname = (SELECT d.dname FROM dept d WHERE e.deptno = d.deptno)
-- 注意:这里没有 WHERE 条件,会更新所有记录
-- 但子查询中的条件 e.deptno = d.deptno 确保了只更新有匹配部门的记录
更多示例:
-- 示例 1:根据订单表更新订单状态
UPDATE orders
SET status = 'Shipped'
WHERE customer_id = (SELECT id FROM customers WHERE name = 'John Doe');
-- 示例 2:根据详情表更新订单表的订单名称
UPDATE t_order t1
SET ordername = (SELECT detailname FROM t_detail
WHERE t_detail.detailclasses = t1.classes)
WHERE t1.orderid = 1;
场景:同时根据其他表更新多个字段
语法(Oracle):
UPDATE table1 alias
SET (column_name, column_name) = (
SELECT column_name, column_name
FROM table2
WHERE table2.column_name = alias.column_name
)
[WHERE column_name = VALUE]
实际例子:
-- 同时更新学生表的姓名和性别(Oracle 语法)
UPDATE stu t
SET (t.NAME, t.SEX) = (SELECT t1.NAME, t1.SEX
FROM stu1 t1
WHERE t1.ID = t.ID)
WHERE EXISTS(SELECT 1 FROM stu1 t2 WHERE t2.ID = t.ID);
逐行代码解释:
-- UPDATE stu t:指定要更新 stu 表,使用别名 t
UPDATE stu t
-- SET (t.NAME, t.SEX) = (子查询):同时更新 NAME 和 SEX 两个字段
-- 子查询返回两个字段:NAME 和 SEX
SET (t.NAME, t.SEX) = (SELECT t1.NAME, t1.SEX
FROM stu1 t1
WHERE t1.ID = t.ID)
-- WHERE EXISTS(...):只更新在 stu1 表中存在对应 ID 的记录
-- 这是非常重要的!如果不加 EXISTS 条件,不匹配的记录会被更新为 NULL
WHERE EXISTS(SELECT 1 FROM stu1 t2 WHERE t2.ID = t.ID);
️ 重要注意事项:
多表关联 UPDATE 的时候,记得要加 EXISTS() 条件,否则不满足条件的记录被 UPDATE 成 NULL。
错误示例:
-- 错误!没有 EXISTS 条件
UPDATE stu t
SET t.NAME = (SELECT t1.NAME FROM stu1 t1 WHERE t1.ID = t.ID);
问题:如果 stu 表中存在某个 ID,但 stu1 表中不存在对应的 ID,那么子查询会返回 NULL,导致 stu 表中该记录的 NAME 字段被更新为 NULL。
正确做法:
-- 正确!添加了 EXISTS 条件
UPDATE stu t
SET t.NAME = (SELECT t1.NAME FROM stu1 t1 WHERE t1.ID = t.ID)
WHERE EXISTS(SELECT 1 FROM stu1 t2 WHERE t2.ID = t.ID);
更多示例:
-- 示例 1:同时更新订单表的订单名称和订单价格
UPDATE t_order t1
SET (ordername, orderprice) = (
SELECT detailname, totalprice
FROM t_detail
WHERE t_detail.detailclasses = t1.classes
)
WHERE t1.orderid = 1;
-- 示例 2:同时更新表 A 的三个字段
UPDATE A
SET (A1, A2, A3) = (SELECT B1, B2, B3 FROM B WHERE A.ID = B.ID)
WHERE ID IN (SELECT B.ID FROM B WHERE A.ID = B.ID);
多表关联更新是指根据多个表之间的关联关系来更新数据。不同数据库的语法略有不同。
语法:
UPDATE table1
INNER|LEFT|RIGHT JOIN table2
ON condition
SET column1 = value1, column2 = value2, ...
[WHERE conditions];
实际例子:
-- 根据用户收入表更新用户余额表
UPDATE $table1 a
INNER JOIN $table2 b
ON a.user_id = b.user_id
SET a.balance = a.balance + b.income, b.status = 1
WHERE b.id = 5 AND b.status = 0;
逐行代码解释:
-- UPDATE $table1 a:指定要更新的主表,使用别名 a
UPDATE $table1 a
-- INNER JOIN $table2 b ON a.user_id = b.user_id:关联表2,关联条件是 user_id 相等
INNER JOIN $table2 b
ON a.user_id = b.user_id
-- SET a.balance = a.balance + b.income, b.status = 1:更新两个表的字段
-- 表1的 balance 字段增加表2的 income 值
-- 表2的 status 字段设置为 1
SET a.balance = a.balance + b.income, b.status = 1
-- WHERE b.id = 5 AND b.status = 0:只更新符合条件的记录
WHERE b.id = 5 AND b.status = 0;
更多示例:
-- 示例 1:使用子查询作为关联表
UPDATE A
INNER JOIN (SELECT B.B1 as B1, B.B2 as B2, C.C1 as C1
FROM B
LEFT JOIN C ON B.B3 = C.C3) as t
ON A.A3 = t.B1
SET A.A1 = t.B2, A.A2 = t.C1;
-- 示例 2:根据图书信息和部门信息更新书架表
UPDATE tb_bookcase
INNER JOIN (SELECT tb_bookinfo.rid as rid, tb_bookinfo.bookname, department.name
FROM tb_bookinfo
LEFT JOIN department ON tb_bookinfo.depid = department.id) as t
ON tb_bookcase.id = t.rid
SET tb_bookcase.bookname = t.bookname, tb_bookcase.departname = t.name;
语法:
UPDATE table1
SET column1 = t2.column1,
column2 = t2.column2,
...
FROM table1
INNER/LEFT/RIGHT JOIN table2
ON table1.column = table2.column
[WHERE conditions]
实际例子:
-- 根据表 B 和表 C 的数据更新表 A
UPDATE A
SET A1 = t2.B2, A2 = t2.C1
FROM A
INNER JOIN (SELECT B.B1, B.B2, C.C1
FROM B
LEFT JOIN C ON B.B3 = C.C3) t2
ON A.A3 = t2.B1
WHERE A.A4 = 1;
逐行代码解释:
-- UPDATE A:指定要更新的表
UPDATE A
-- SET A1 = t2.B2, A2 = t2.C1:设置要更新的字段
SET A1 = t2.B2, A2 = t2.C1
-- FROM A INNER JOIN ...:在 FROM 子句中指定关联关系
FROM A
INNER JOIN (SELECT B.B1, B.B2, C.C1
FROM B
LEFT JOIN C ON B.B3 = C.C3) t2
ON A.A3 = t2.B1
-- WHERE A.A4 = 1:指定更新条件
WHERE A.A4 = 1;
更多示例:
-- 示例 1:根据订单表和详情表更新异常费用表
UPDATE t_abnormal_fee
SET order_code = t2.order_code, return_fee = t2.express_fee
FROM t_abnormal_fee
INNER JOIN (SELECT t_order.id, t_order.order_code, t_detail.express_fee
FROM t_order
LEFT JOIN t_detail ON t_order.name = t_detail.name) t2
ON t_abnormal_fee.id = t2.id
WHERE t_abnormal_fee.id = 1;
场景:使用子查询方式实现多表关联更新
语法:
UPDATE t1
SET t1.`name` = (SELECT t2.`name` FROM t2 WHERE t1.id = t2.id)
WHERE EXISTS(SELECT 1 FROM t2 WHERE t2.id = t1.id);
实际例子:
-- 根据表 t2 更新表 t1 的 name 字段
UPDATE t1
SET t1.`name` = (SELECT t2.`name` FROM t2 WHERE t1.id = t2.id)
WHERE EXISTS(SELECT 1 FROM t2 WHERE t2.id = t1.id);
逐行代码解释:
-- UPDATE t1:指定要更新的表
UPDATE t1
-- SET t1.`name` = (子查询):将 name 字段设置为子查询的结果
SET t1.`name` = (SELECT t2.`name` FROM t2 WHERE t1.id = t2.id)
-- WHERE EXISTS(...):只更新在 t2 表中存在对应 id 的记录
-- 这是非常重要的!避免将不匹配的记录更新为 NULL
WHERE EXISTS(SELECT 1 FROM t2 WHERE t2.id = t1.id);
不同数据库对 UPDATE 语句的支持略有不同,特别是在多表关联更新方面。让我们来看看主要数据库的差异。
特点:
sql_safe_updates 强制要求 WHERE 条件多表更新语法:
UPDATE table1
INNER JOIN table2 ON condition
SET column1 = value1
WHERE condition;
安全模式设置:
-- 开启安全更新模式,强制要求 WHERE 条件
SET sql_safe_updates = 1;
返回结果示例:
-- 更新 id=1 的记录
mysql> UPDATE students SET name='大宝' WHERE id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
-- 更新 id=999 的记录(不存在)
mysql> UPDATE students SET name='大宝' WHERE id=999;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0
特点:
多字段更新语法:
UPDATE table1 alias
SET (column_name, column_name) = (
SELECT column_name, column_name
FROM table2
WHERE table2.column_name = alias.column_name
)
[WHERE column_name = VALUE]
特点:
多表更新语法:
UPDATE table1
SET column1 = t2.column1
FROM table1
INNER JOIN table2 ON condition
WHERE condition;
特点:
UPSERT 语法:
INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...)
ON CONFLICT (conflict_column)
DO UPDATE SET column1 = EXCLUDED.column1;
| 数据库 | 多表更新语法 | 特点 |
|---|---|---|
| MySQL | UPDATE t1 JOIN t2 ON ... SET ... | 支持 JOIN,语法简洁 |
| SQL Server | UPDATE t1 SET ... FROM t1 JOIN t2 ON ... | 使用 FROM 子句 |
| Oracle | UPDATE t1 SET (col1, col2) = (SELECT ...) | 支持多字段子查询更新 |
| PostgreSQL | UPDATE t1 SET ... FROM t2 WHERE ... | 类似 SQL Server,支持 UPSERT |
在使用 UPDATE 语句时,有一些重要的注意事项和警告需要牢记。
重要警告:在更新记录时要格外小心!如果省略了 WHERE 子句,所有的记录都将被更新!
错误示例:
-- 危险!这会更新所有记录
UPDATE Customers
SET ContactName = 'Juan';
执行结果:表中所有记录的 ContactName 字段都会被更新为 'Juan',这通常不是我们想要的结果!
正确做法:
sql_safe_updates 模式执行没有 WHERE 子句的 UPDATE 要慎重,再慎重!
在执行 UPDATE 语句时,务必谨慎,因为一旦执行,就会直接修改数据库中的数据。
建议流程:
-- 第一步:先用 SELECT 查看会更新哪些记录
SELECT * FROM students WHERE score < 80;
-- 第二步:确认无误后,再执行 UPDATE
UPDATE students
SET score = score + 10
WHERE score < 80;
测试环境验证:
备份数据:
️ 重要提醒:多表关联 UPDATE 的时候,记得要加 EXISTS() 条件,否则不满足条件的记录被 UPDATE 成 NULL。
错误示例:
-- 错误!没有 EXISTS 条件
UPDATE stu t
SET t.NAME = (SELECT t1.NAME FROM stu1 t1 WHERE t1.ID = t.ID);
问题:如果 stu 表中存在某个 ID,但 stu1 表中不存在对应的 ID,那么子查询会返回 NULL,导致 stu 表中该记录的 NAME 字段被更新为 NULL。
正确做法:
-- 正确!添加了 EXISTS 条件
UPDATE stu t
SET t.NAME = (SELECT t1.NAME FROM stu1 t1 WHERE t1.ID = t.ID)
WHERE EXISTS(SELECT 1 FROM stu1 t2 WHERE t2.ID = t.ID);
如果 WHERE 条件没有匹配到任何记录,UPDATE 语句不会报错,也不会有任何记录被更新。
示例:
-- 更新 id 为 999 的记录(假设不存在)
UPDATE students
SET score = 100
WHERE id = 999;
执行结果:
Rows matched: 0 Changed: 0建议:如果需要确认是否有记录被更新,可以检查 UPDATE 语句的返回结果。
为了删除某个列的值,可设置它为 NULL(假定表定义允许 NULL 值)。
语法:
UPDATE table_name
SET column_name = NULL
WHERE condition;
示例:
-- 将某个学生的备注字段清空
UPDATE students
SET remark = NULL
WHERE id = 1;
注意事项:
在实际应用中,UPDATE 语句的性能优化非常重要,特别是当需要更新大量数据时。
对于 UPDATE 语句中涉及的列,确保相应的列上建有索引,以提高检索速度。
示例:
-- 如果经常根据 id 更新记录,确保 id 字段有索引
-- 创建索引
CREATE INDEX idx_students_id ON students(id);
-- 使用索引的 UPDATE 语句会更快
UPDATE students
SET score = 95
WHERE id = 1; -- id 字段有索引,查询速度更快
注意事项:
当需要更新大量数据时,可以分批进行更新,避免一次性更新过多数据影响性能。
示例:
-- 方式 1:使用 LIMIT 分批更新(MySQL)
UPDATE students
SET score = score + 10
WHERE score < 80
LIMIT 1000; -- 每次只更新 1000 条
-- 方式 2:使用循环分批更新
-- 第一次更新 id 1-1000
UPDATE students
SET score = score + 10
WHERE score < 80 AND id BETWEEN 1 AND 1000;
-- 第二次更新 id 1001-2000
UPDATE students
SET score = score + 10
WHERE score < 80 AND id BETWEEN 1001 AND 2000;
优势:
在更新大量数据时,考虑使用事务来确保数据的一致性。
示例:
-- 开始事务
START TRANSACTION;
-- 执行更新操作
UPDATE students
SET score = score + 10
WHERE score < 80;
-- 检查更新结果
SELECT COUNT(*) FROM students WHERE score >= 80;
-- 如果结果正确,提交事务
COMMIT;
-- 如果结果不正确,回滚事务
-- ROLLBACK;
优势:
在 MySQL 中,当执行 UPDATE xxxx WHERE topic_id = xxx 时,MySQL 会对 topic_id 索引加行锁。
问题场景: 在高并发场景下,如果多个操作在同一个事务中,行锁的持有时间会延长。可以通过调整操作顺序来降低行锁的持有粒度。
优化示例:
原逻辑(性能较差):
START TRANSACTION;
-- 第一步:UPDATE(加行锁)
UPDATE topics SET submit_count = submit_count + 1 WHERE topic_id = 1;
-- 第二步:INSERT(行锁一直持有,直到事务结束)
INSERT INTO results (topic_id, result) VALUES (1, 'AC');
COMMIT;
优化后(性能更好):
START TRANSACTION;
-- 第一步:INSERT(不加行锁或加锁时间短)
INSERT INTO results (topic_id, result) VALUES (1, 'AC');
-- 第二步:UPDATE(行锁持有时间短)
UPDATE topics SET submit_count = submit_count + 1 WHERE topic_id = 1;
COMMIT;
实际案例: 通过调整 UPDATE 和 INSERT 的执行顺序,判题结果写库的逻辑从原来的 400 TPS 直接拉高到 2000 多 TPS。
原理:
大数据更新要注意:
️ 重要提醒:如果更新条件不精准,可能导致大面积锁表,影响其他业务。
通过对比示例,我们可以更清楚地看到 UPDATE 语句的价值和正确用法。
场景:需要修改学生表中某个学生的成绩
不使用 UPDATE(繁琐且容易出错):
-- 第一步:删除旧记录
DELETE FROM students WHERE id = 1;
-- 第二步:插入新记录
INSERT INTO students (id, name, age, score)
VALUES (1, '张三', 20, 95);
问题:
使用 UPDATE(简单且安全):
-- 一条语句完成更新
UPDATE students
SET score = 95
WHERE id = 1;
优势:
场景:更新所有 VIP 用户的积分
错误写法(忘记 WHERE 条件):
-- 危险!这会更新所有用户的积分
UPDATE users
SET points = points + 100;
问题:
正确写法(使用 WHERE 条件):
-- 正确!只更新 VIP 用户的积分
UPDATE users
SET points = points + 100
WHERE user_type = 'VIP';
优势:
场景:更新 10000 条记录的成绩
低效方式(逐条更新):
-- 需要执行 10000 次 UPDATE 语句
UPDATE students SET score = 95 WHERE id = 1;
UPDATE students SET score = 95 WHERE id = 2;
UPDATE students SET score = 95 WHERE id = 3;
-- ... 重复 10000 次
问题:
高效方式(批量更新):
-- 一条语句更新所有记录
UPDATE students
SET score = 95
WHERE id BETWEEN 1 AND 10000;
优势:
在使用 UPDATE 语句时,有一些常见的错误需要注意和避免。
错误现象:
-- 错误!忘记 WHERE 子句
UPDATE students
SET score = 95;
问题:所有学生的成绩都会被更新为 95,这通常不是我们想要的结果!
修正方法:
-- 正确!添加 WHERE 条件
UPDATE students
SET score = 95
WHERE id = 1;
预防措施:
sql_safe_updates 模式错误现象:
-- 错误!没有 EXISTS 条件
UPDATE stu t
SET t.NAME = (SELECT t1.NAME FROM stu1 t1 WHERE t1.ID = t.ID);
问题:如果 stu 表中存在某个 ID,但 stu1 表中不存在对应的 ID,那么该记录的 NAME 字段会被更新为 NULL。
修正方法:
-- 正确!添加 EXISTS 条件
UPDATE stu t
SET t.NAME = (SELECT t1.NAME FROM stu1 t1 WHERE t1.ID = t.ID)
WHERE EXISTS(SELECT 1 FROM stu1 t2 WHERE t2.ID = t.ID);
预防措施:
错误现象:
-- 错误!更新条件不精准,可能锁住大量记录
UPDATE orders
SET status = 'Shipped'
WHERE status = 'Pending'; -- 如果 Pending 订单有 100 万条
问题:如果符合条件的记录很多,可能导致大面积锁表,影响其他业务。
修正方法:
-- 正确!分批更新,减少锁表时间
-- 第一次更新 id 1-10000
UPDATE orders
SET status = 'Shipped'
WHERE status = 'Pending' AND id BETWEEN 1 AND 10000;
-- 第二次更新 id 10001-20000
UPDATE orders
SET status = 'Shipped'
WHERE status = 'Pending' AND id BETWEEN 10001 AND 20000;
预防措施:
错误现象:
-- 错误!字符串和数字直接相加
UPDATE students
SET name = name + 10
WHERE id = 1;
问题:字符串和数字类型不匹配,可能导致错误或意外结果。
修正方法:
-- 正确!确保表达式类型匹配
UPDATE students
SET score = score + 10
WHERE id = 1;
预防措施:
让我们通过一些实际的应用案例来加深对 UPDATE 语句的理解。
场景:用户修改个人资料,需要更新用户表中的信息
SQL 语句:
-- 更新用户表中 id 为 1 的用户名
UPDATE users
SET username = '新用户名'
WHERE user_id = 1;
说明:
场景:活动期间,给所有用户增加 10 积分
SQL 语句:
-- 给所有用户的积分增加 10 分
UPDATE users
SET points = points + 10;
说明:
场景:将某个客户的所有订单状态更新为"已发货"
SQL 语句:
-- 更新客户 id 为 1 的所有订单状态
UPDATE orders
SET status = 'Shipped'
WHERE customer_id = 1;
说明:
场景:将所有价格低于 100 的商品价格提高 10%
SQL 语句:
-- 将价格低于 100 的商品价格提高 10%
UPDATE products
SET price = price * 1.1
WHERE price < 100;
说明:
price * 1.1 计算新价格场景:根据部门表更新员工表的部门名称
SQL 语句:
-- 根据部门表更新员工表的部门名称
UPDATE emp e
SET e.dname = (SELECT d.dname FROM dept d WHERE e.deptno = d.deptno);
说明:
业务背景:一个类似于力扣在线做题的代码评测模块,用户提交判题任务后,后台会进行异步判题。
问题:大量的用户在前端提交后,一直都轮询不到判题结果。判题结果写库逻辑耗时 1 秒多。
原因分析:
UPDATE xxxx WHERE topic_id = xxx 时,MySQL 会对 topic_id 索引加行锁解决方案: 将 1、2 两个步骤交换下顺序:
这样可以降低行锁的持有粒度。
效果:判题结果写库的逻辑从原来的 400 TPS 直接拉高到 2000 多 TPS。
通过本文档的学习,我们掌握了 SQL UPDATE 语句的核心知识点和实用技巧。让我们来总结一下关键要点:
UPDATE 基本语法 Must
UPDATE table_name SET column = value WHERE condition单表更新 Must
表达式更新 ⭐ Should
SET score = score + 10子查询更新 ⭐ Should
多表关联更新 ⭐ Should
性能优化 Could
UPDATE 语句是数据库中非常重要的操作之一,通过灵活运用 UPDATE 语句,我们可以高效地对数据库中的数据进行更新。在日常开发中,更新数据(UPDATE)是仅次于 SELECT 的常用 SQL 操作。
掌握 UPDATE 语句的关键在于:
希望本文档能够帮助你掌握 SQL UPDATE 语句的核心技能,在实际工作中灵活运用,提高开发效率,避免数据灾难。让我们一起在 SQL 学习的道路上不断进步!
作者:郑恩赐
机构:厦门工学院人工智能创作坊
日期:2025 年 11 月 11 日