SQL增删改查完整指南:INSERT/UPDATE/DELETE实战

0 阅读9分钟

前言

上篇讲了SQL查询的10个核心语句,这篇讲SQL的另一半:数据操作

查询(SELECT)是"看数据",而增删改(INSERT/UPDATE/DELETE)是"动数据"。

很多同学学了SELECT就以为自己会SQL了,结果一到实际工作中——录入数据不会INSERT,改错了不会UPDATE,删错了不会回滚

今天这篇,把INSERT、UPDATE、DELETE三个语句讲透,外加事务控制,确保你不会因为误操作把数据库搞崩。

建议:先看上篇《SQL零基础入门:10个语句解决80%的查询问题》,再看这篇,效果翻倍。

〇、建表准备

和上篇一样,基于电商订单表来演示。如果上篇的表还在,这步可以跳过。

-- ============================================
-- 电商订单表 orders
-- 公主号:船长Talk
-- ============================================

CREATE TABLE orders (
    order_id     INT PRIMARY KEY COMMENT '订单ID',
    customer     VARCHAR(50) COMMENT '客户姓名',
    product      VARCHAR(100) COMMENT '商品名称',
    category     VARCHAR(50) COMMENT '商品分类',
    price        DECIMAL(10,2) COMMENT '单价',
    quantity     INT COMMENT '购买数量',
    total_amount DECIMAL(10,2) COMMENT '订单总金额',
    order_date   DATE COMMENT '下单日期',
    status       VARCHAR(20) COMMENT '订单状态'
);

-- 插入初始测试数据
INSERT INTO orders VALUES
(1,  '张三', 'iPhone 15',     '手机',   7999.00, 1, 7999.00, '2026-04-01', '已发货'),
(2,  '李四', 'MacBook Pro',    '电脑',  14999.00, 1,14999.00, '2026-04-01', '已完成'),
(3,  '张三', 'AirPods Pro',    '配件',    999.00, 2, 1998.00, '2026-04-02', '已完成'),
(4,  '王五', 'iPhone 15',      '手机',   7999.00, 1, 7999.00, '2026-04-02', '待发货'),
(5,  '赵六', 'iPad Air',       '平板',   4799.00, 2, 9598.00, '2026-04-03', '已取消'),
(6,  '李四', 'Apple Watch',    '配件',   2999.00, 1, 2999.00, '2026-04-03', '已完成'),
(7,  '张三', 'MacBook Pro',    '电脑',  14999.00, 1,14999.00, '2026-04-04', '待发货'),
(8,  '王五', 'Magic Keyboard', '配件',   1999.00, 1, 1999.00, '2026-04-05', '已发货'),
(9,  '赵六', 'iPhone 15',      '手机',   7999.00, 1, 7999.00, '2026-04-05', '已完成'),
(10, '张三', 'HomePod mini',   '配件',    749.00, 2, 1498.00, '2026-04-06', '已完成');

一、INSERT —— 插入数据

**用途:**往表里新增一行或多行数据。这是所有数据操作的起点——没有INSERT,表就是空的。

1.1 基础插入:一次插入一行

-- ============================================
-- INSERT 基础用法
-- 公主号:船长Talk
-- ============================================

-- 最基本的插入(按列的顺序填值)
INSERT INTO orders 
VALUES (11, '孙七', 'AirPods 3', '配件', 1399.00, 1, 1399.00, '2026-04-07', '待发货');

-- 指定列名插入(推荐!不依赖列的顺序,更安全)
INSERT INTO orders 
    (order_id, customer, product, category, price, quantity, total_amount, order_date, status) 
VALUES 
    (12, '周八', 'iPad mini', '平板', 3799.00, 2, 7598.00, '2026-04-07', '已完成');

**实战建议:**永远用"指定列名"的方式插入。如果以后表加了新列,不指定列名的写法会直接报错。

1.2 批量插入:一次插入多行

-- 批量插入(效率远高于循环单条插入)
-- 场景:数据迁移、批量导入
INSERT INTO orders VALUES
    (13, '孙七', 'Apple Pencil', '配件',  999.00, 2, 1998.00, '2026-04-08', '已完成'),
    (14, '周八', 'iPhone 15',    '手机',  7999.00, 1, 7999.00, '2026-04-08', '待发货'),
    (15, '吴九', 'MacBook Air',  '电脑',  8999.00, 1, 8999.00, '2026-04-08', '已发货');

**性能提示:**批量插入比循环单条INSERT快10-100倍。导入10万条数据,批量插入可能只要30秒,循环单条可能要10分钟。

1.3 插入查询结果:INSERT INTO ... SELECT

-- 把一个查询结果插入到另一张表
-- 场景:数据备份、报表归档

-- 先创建历史订单表(结构和orders一样)
CREATE TABLE orders_history LIKE orders;

-- 把已完成的订单归档到历史表
INSERT INTO orders_history
SELECT * FROM orders WHERE status = '已完成';

-- 验证:历史表里有多少条
SELECT COUNT(*) AS '归档订单数' FROM orders_history;

**实战场景:**每月把上月的已完成订单归档到历史表,主表只保留近3个月的数据,查询更快。

1.4 插入时处理冲突:ON DUPLICATE KEY UPDATE

-- MySQL特有语法:如果主键冲突,就更新而不是报错
-- 场景:用户积分系统——每天更新,没有就新增

-- 创建用户积分表
CREATE TABLE user_points (
    user_id    INT PRIMARY KEY COMMENT '用户ID',
    points     INT DEFAULT 0 COMMENT '积分余额',
    level      VARCHAR(20) DEFAULT '普通会员' COMMENT '会员等级',
    updated_at DATE COMMENT '最后更新日期'
);

-- 第一次插入(不存在,直接新增)
INSERT INTO user_points (user_id, points, level, updated_at)
VALUES (1001, 500, '银牌会员', '2026-04-07')
ON DUPLICATE KEY UPDATE 
    points = points + VALUES(points),
    level  = CASE 
        WHEN points + VALUES(points) >= 5000 THEN '金牌会员'
        WHEN points + VALUES(points) >= 1000 THEN '银牌会员'
        ELSE '铜牌会员'
    END,
    updated_at = '2026-04-07';

-- 再执行一次(已存在,自动累加积分)
INSERT INTO user_points (user_id, points, level, updated_at)
VALUES (1001, 200, '银牌会员', '2026-04-08')
ON DUPLICATE KEY UPDATE 
    points = points + VALUES(points),
    updated_at = '2026-04-08';

-- 查看结果:积分应该是 500 + 200 = 700
SELECT * FROM user_points WHERE user_id = 1001;

**核心价值:**不用先SELECT判断存不存在,再决定INSERT还是UPDATE。一条语句搞定,代码更简洁,也不会有并发问题。

二、UPDATE —— 修改数据

**用途:**修改表中已有的数据。这是工作中最危险的操作之一——忘了加WHERE,全表都会被改

2.1 基础更新

-- ============================================
-- UPDATE 基础用法
-- 公主号:船长Talk
-- ============================================

-- 修改单个字段:把订单4的状态改为"已发货"
UPDATE orders SET status = '已发货' WHERE order_id = 4;

-- 修改多个字段:同时改状态和日期
UPDATE orders 
SET status = '已完成', 
    order_date = '2026-04-08' 
WHERE order_id = 4;

-- ⚠️ 危险操作演示(千万别在生产环境跑!)
-- 忘了加WHERE,所有订单的状态都会被改掉
-- UPDATE orders SET status = '已完成';

**铁律:**UPDATE语句必须有WHERE条件。写完UPDATE先看一眼有没有WHERE,没有就别执行。

2.2 条件更新:批量修改

-- 把所有"待发货"的订单改为"已发货"
UPDATE orders SET status = '已发货' WHERE status = '待发货';

-- 给所有手机品类的订单打9折
UPDATE orders 
SET price = ROUND(price * 0.9, 2),
    total_amount = ROUND(quantity * price * 0.9, 2)
WHERE category = '手机';

-- 给张三的所有已完成订单备注(需要有remark字段才能用)
-- 如果表没有remark字段,先加:ALTER TABLE orders ADD COLUMN remark VARCHAR(200);
ALTER TABLE orders ADD COLUMN remark VARCHAR(200) DEFAULT NULL;
UPDATE orders SET remark = 'VIP客户订单' WHERE customer = '张三' AND status = '已完成';

2.3 基于其他表的数据更新

-- 创建折扣表
CREATE TABLE discounts (
    category  VARCHAR(50) PRIMARY KEY COMMENT '品类',
    rate      DECIMAL(3,2) COMMENT '折扣率'
);

INSERT INTO discounts VALUES
    ('手机', 0.90),
    ('电脑', 0.95),
    ('配件', 0.85),
    ('平板', 0.92);

-- 用折扣表批量更新订单价格
UPDATE orders o
INNER JOIN discounts d ON o.category = d.category
SET o.price = ROUND(o.price * d.rate, 2),
    o.total_amount = ROUND(o.quantity * o.price * d.rate, 2)
WHERE o.status = '待发货';

**实战场景:**运营部门给不同品类设置折扣,你用一条UPDATE批量应用,不用每个品类单独写。

2.4 UPDATE + CASE WHEN:复杂条件更新

-- 根据消费金额自动升级客户等级(需要在orders表加level字段)
ALTER TABLE orders ADD COLUMN customer_level VARCHAR(20) DEFAULT NULL;

-- 一次UPDATE,用CASE WHEN判断不同条件
UPDATE orders
SET customer_level = CASE
    WHEN total_amount >= 10000 THEN 'A-大客户'
    WHEN total_amount >= 5000  THEN 'B-中客户'
    WHEN total_amount >= 1000  THEN 'C-小客户'
    ELSE 'D-散客'
END;

-- 验证结果
SELECT customer_level, COUNT(*) AS '订单数', ROUND(AVG(total_amount),2) AS '平均金额'
FROM orders GROUP BY customer_level ORDER BY 平均金额 DESC;

三、DELETE —— 删除数据

用途:删除表中的数据。这是最危险的操作,没有之一

**铁律:**DELETE之前先用SELECT查一遍确认范围,然后用事务包裹。

3.1 基础删除

-- ============================================
-- DELETE 基础用法
-- 公主号:船长Talk
-- ============================================

-- 删除指定行
DELETE FROM orders WHERE order_id = 15;

-- 删除满足条件的行:删除所有已取消的订单
DELETE FROM orders WHERE status = '已取消';

-- ⚠️ 危险操作!删除全表数据(千万别在生产环境跑!)
-- DELETE FROM orders;  -- 没有WHERE = 删光所有数据

**安全习惯:**删除前先SELECT,确认数据范围。

-- 第一步:先看看要删哪些数据
SELECT * FROM orders WHERE status = '已取消';

-- 第二步:确认无误后再删
DELETE FROM orders WHERE status = '已取消';

3.2 DELETE vs TRUNCATE vs DROP

-- 三种"删除"的区别(非常重要)

-- 1. DELETE:逐行删除,记录日志,可以回滚(慢)
DELETE FROM orders WHERE status = '已取消';

-- 2. TRUNCATE:清空整张表,不记录日志,不可回滚(极快)
TRUNCATE TABLE orders_history;

-- 3. DROP:删除整张表(结构和数据都没了)
DROP TABLE IF EXISTS temp_table;

速查表:

  操作
  范围
  WHERE条件
  可回滚
  速度

  `DELETE`
  部分行或全部
  ✅ 支持
  ✅ 事务内可回滚
  慢(逐行删除)

  `TRUNCATE`
  整张表
  ❌ 不支持
  ❌ 不可回滚
  极快(DDL操作)

  `DROP`
  整张表(含结构)
  ❌ 不支持
  ❌ 不可回滚
  快

3.3 关联删除:基于其他表的数据删除

-- 删除在历史表中已归档的订单
-- 场景:主表清理,只保留最近活跃数据

DELETE o FROM orders o
INNER JOIN orders_history h ON o.order_id = h.order_id
WHERE h.status = '已完成' AND h.order_date  180;

-- 6. 自动升级等级
UPDATE user_points
SET level = CASE
    WHEN points >= 10000 THEN '钻石会员'
    WHEN points >= 5000  THEN '金牌会员'
    WHEN points >= 1000  THEN '银牌会员'
    WHEN points >= 100   THEN '铜牌会员'
    ELSE '普通会员'
END;

-- 全部成功,提交
COMMIT;

-- 7. 查看最终结果
SELECT user_id, username, points, level, updated_at 
FROM user_points 
ORDER BY points DESC;

六、安全操作清单

在正式操作数据之前,对照这个清单检查一遍:

  操作
  安全检查项

  INSERT
  是否指定了列名?数据类型是否匹配?有没有主键冲突?

  UPDATE
  有没有WHERE?先用SELECT确认范围?是否在事务内?

  DELETE
  有没有WHERE?先用SELECT确认范围?是否在事务内?是否需要备份?

  事务
  START TRANSACTION写了?操作验证了?COMMIT/ROLLBACK别忘记?

写在最后

INSERT/UPDATE/DELETE + 事务控制,这是SQL数据操作的完整闭环。

和上篇的查询语句组合起来,你已经掌握了SQL的全部基础操作

  • 查询:SELECT / WHERE / ORDER BY / GROUP BY / HAVING(上篇)

  • 写入:INSERT(本篇)

  • 修改:UPDATE(本篇)

  • 删除:DELETE(本篇)

  • 安全:事务控制(本篇)

下一步:

  • 进阶学习:JOIN多表查询(下篇更新)

  • 面试准备:SQL面试50题(关注公主号,持续更新)

  • 完整代码:后台私信"sql 代码",获取建表SQL + 全部练习代码

-- 公主号:船长Talk
-- 更多数据分析干货(SQL/Python/机器学习),持续更新
-- 有问题欢迎评论区留言,船长看到都会回复

觉得有用的话,点赞收藏,转给身边学SQL的朋友。下一篇讲JOIN多表查询,不想错过就关注一下。