Skip to content

更新 / 删除(UPDATE/DELETE)/ 计算列

UPDATE 更新数据

基本语法

sql
UPDATE student
SET score = 90
WHERE name = '张三';

危险:没有 WHERE 的 UPDATE 会更新所有行!

sql
UPDATE student SET score = 0;  -- 所有学生的成绩都变成 0!

批量更新多列

sql
UPDATE student
SET age = age + 1,
    score = score + 5
WHERE class_id = 1;

UPDATE + 子查询

sql
-- 把班级平均分以下的同学成绩加 10 分
UPDATE student
SET score = score + 10
WHERE score < (
    SELECT avg_score FROM (
        SELECT AVG(score) AS avg_score FROM student
    ) AS t
);

这里用了派生表绕开「不能更新同一张表的子查询」限制。

UPDATE + ORDER BY + LIMIT

sql
-- 按成绩从低到高更新,取最低的 10 个人加 5 分
UPDATE student
SET score = score + 5
ORDER BY score ASC
LIMIT 10;

UPDATE 多表

sql
-- 一次更新两张表
UPDATE student s
JOIN class c ON s.class_id = c.id
SET s.score = s.score + 10
WHERE c.name = '一班';

DELETE 删除数据

基本语法

sql
DELETE FROM student
WHERE name = '张三';

危险:没有 WHERE 的 DELETE 会删除所有行!

sql
DELETE FROM student;  -- 所有数据都没了!

DELETE + ORDER BY + LIMIT

sql
-- 删除成绩最低的 3 名学生
DELETE FROM student
ORDER BY score ASC
LIMIT 3;

DELETE 多表

sql
-- 从两个表中删除满足条件的数据
DELETE s, e
FROM student s
JOIN enrollment e ON s.id = e.student_id
WHERE s.score < 30;

DELETE 与 TRUNCATE 的区别

特性DELETETRUNCATE
类型DMLDDL
WHERE 条件✅ 支持❌ 不支持
速度慢(逐行删除)快(重建表)
回滚✅ 可回滚❌ 不可回滚
AUTO_INCREMENT❌ 不重置✅ 重置
触发器✅ 触发❌ 不触发

计算列(Generated Column)

计算列是 MySQL 5.7.7+ 引入的特性——由其他列计算得出,存储时自动计算。

语法

sql
CREATE TABLE order_info (
    price     DECIMAL(10,2),
    quantity  INT,
    -- 计算列:总价 = 单价 × 数量
    total_price DECIMAL(10,2) AS (price * quantity) STORED,
    -- AS (表达式):定义计算列
    -- STORED:计算后存储(物理占用空间,可建索引)
    -- VIRTUAL:不存储,查询时实时计算(不占空间)
    discount_rate DECIMAL(3,2) DEFAULT 0.10,
    final_price DECIMAL(10,2) AS ((price * quantity) * (1 - discount_rate)) STORED
);

STORED vs VIRTUAL

特性STOREDVIRTUAL
存储空间占磁盘空间不占空间
索引✅ 可以建索引❌ 不可以
查询性能快(直接读)稍慢(实时算)
适用场景需要排序/索引简单表达式

计算列建索引

sql
-- 用计算列建索引(只有 STORED 支持)
CREATE TABLE t (
    a INT,
    b INT,
    c INT AS (a + b) STORED,
    INDEX idx_c (c)
);

-- 这个查询可以使用索引
SELECT * FROM t WHERE c > 100;

实战:用户年龄计算

sql
CREATE TABLE user (
    id BIGINT PRIMARY KEY,
    name VARCHAR(50),
    birth_date DATE,
    -- 每年自动更新,不用手动维护
    age INT AS (TIMESTAMPDIFF(YEAR, birth_date, CURDATE())) VIRTUAL
);

事务中的 UPDATE / DELETE

在事务包裹下的 UPDATE 和 DELETE 可以回滚:

sql
START TRANSACTION;
UPDATE account SET balance = balance - 1000 WHERE id = 1;
UPDATE account SET balance = balance + 1000 WHERE id = 2;
-- 检查结果
SELECT * FROM account WHERE id IN (1, 2);
-- 确认无误后提交
COMMIT;
-- 或者发现问题后回滚
-- ROLLBACK;

下一步

数据操作学完了,接下来看 事务控制(COMMIT/ROLLBACK)

基于 VitePress 构建