🦏 第7章 数据修改
📄 一句话概括

insert 增行、update 改行、delete 删行。 它们和 select 的根本区别是:select 只读,它们会改。 改了就没有撤销,所以写法习惯和查询完全相反:先想清楚范围,再动手。 唯一的反馈是「影响几行」:影响 1 行是「改了一行」, 影响 0 行是「条件没匹配上」——不是失败。

📝 本章和前面几章的关系

前六章全在「取」——取列、筛行、分组、算、套函数。 这一章开始「改」。 这是全书第一次碰到「不可逆」的操作。 之前的错顶多输出不对, 这一章的错会把数据弄丢。 所以这一章的每一篇都带着安全习惯讲。

一、三类语句,一个共同点:不可逆

insert 加行、update 改行、delete 删行。 语法各异,但都是「改数据」这一类的。 select 跑错了,最多是结果不对;update 跑错了,数据就变了。 而且没有「撤销」——除非事先备份过。 所以这三类语句的写法要跟查询反着来: 查询可以随手写写试试,改数据要先想清楚「改哪些行」。 想清楚的手段,就是下面几段那几个习惯。

二、影响几行:唯一的反馈

语句跑完只告诉你一个数:影响了几行。 改一行就是「影响 1 行」,删除四行就是「影响 4 行」。 它不等于「成功」。 「影响 0 行」看着像成功,其实是条件一行都没匹配上—— 可能是 where 写错了,也可能本来就没有符合条件的行。 分不清这两者,就会以为改了其实没改。 所以每次改完,都该再 select 一次确认。 这个「改完回读」的动作,比任何技巧都管用。

三、where 是安全绳:不写就是全表

update 表 set 列 = 值 后面不写 where,默认范围就是「所有行」。 Demo 里三行全被改成「临时」。 这是改数据最经典的事故:本来只想改一条,少打一行 where,整张表被覆盖,而且没有撤销。 那一行 where 不是可选项,是必须项。 真需要全表改时,也该显式写 where 1 = 1, 让读代码的人一眼看出「这是有意的全表操作」。

四、两个保命习惯:空跑与先查

习惯一:把 where 先拿去做 select。 想知道会改到哪几行, 先跑 SELECT * FROM 表 WHERE 条件,人对了,再把同一段条件粘到 update 上。 习惯二:where 1 = 0 空跑一次。 1 = 0 永远不成立,所以影响 0 行、什么都没改, 但语句本身跑通了——能提前发现列名写错、类型不匹配这些问题。 还有第零个习惯:先备份。 CREATE TABLE 备份 AS SELECT * FROM 原表 一行就够, 改坏了还能从备份里捞回来。 第 15 章讲备份时会细讲。

五、多条语句要一起成功:事务

转账要改两张表:A 减 100、B 加 100。 如果第一条成功、第二条失败,钱就凭空消失了。 事务解决的就是这件事:begin 开始,全部成功就 commit, 中间出任何错就 rollback,一切回到起点。 本沙箱用 Python 的 commit / rollback 模拟, MySQL 里是 START TRANSACTION / COMMIT / ROLLBACK。 第 18 章专讲,这里先知道有这件武器。

六、动手 Demo:改一行、改全表、空跑、备份

Demo 五段:改一行看影响行数,不写 where 改全表,用 where 1 = 0 空跑,最后做一次表备份。 这一段没有新语法,全是「怎么不把自己坑了」的动作。

import _q46 as Q
c = Q.con()

# 改一行,看影响几行
c.execute("SELECT id, name, teacher FROM classes WHERE id = 2")
Q.run(c, "UPDATE classes SET teacher = '孔老师(代)' WHERE id = 2")
c.execute("SELECT id, name, teacher FROM classes WHERE id = 2")

# 不写 where:全表都改
c2 = Q.con()
Q.run(c2, "UPDATE classes SET teacher = '临时'")

# 空跑:where 1 = 0 永远不成立
c3 = Q.con()
Q.run(c3, "UPDATE classes SET teacher = '不会生效' WHERE 1 = 0")

# 动手前先备份
c4 = Q.con()
Q.run(c4, "CREATE TABLE classes_bak AS SELECT * FROM classes")
c4.execute("SELECT name FROM sqlite_master WHERE type = 'table'")

实跑输出:

--------------------------------------------------------------------
第三十一课:会改数据的语句,和「影响几行」这个唯一反馈
--------------------------------------------------------------------

  三类语句:增、改、删
  **`insert` 增加行、`update` 修改行、`delete` 删除行。**
  **它们和 `select` 最大的区别是:`select` 只读,它们会改。**
  **改了就回不去**(除非有备份)。
  **所以这三类语句的写法习惯,和查询完全不一样:先想清楚范围,再动手。**

  第一个例子:改一行,看影响几行
  SQL> SELECT id, name, teacher FROM classes WHERE id = 2
  id     name     teacher
  ------------------------
  2      二班     孔老师
  (1 行)

  SQL> UPDATE classes SET teacher = '孔老师(代)' WHERE id = 2
  影响 1 行

  SQL> SELECT id, name, teacher FROM classes WHERE id = 2
  id     name     teacher
  -----------------------------
  2      二班     孔老师(代)
  (1 行)

  **`影响 1 行` 就是这次改动的唯一反馈。** **它不是「成功」的意思,是「改了 1 行」的意思。**
  **如果显示「影响 0 行」,说明 `where` 一行都没匹配上**——
  **条件写错了,不是语句失败了。** 这个区分很要紧。

  where 是安全绳:不写就是全表
  SQL> UPDATE classes SET teacher = '临时'
  影响 3 行

  SQL> SELECT COUNT(*) AS all_rows FROM classes WHERE teacher = '临时'
  all_rows
  ---------
  3
  (1 行)

  **三行全改了。** **因为没写 `where`,「所有行」就是默认范围。**
  **这是改数据最经典的事故**:本来只想改一条,手一抖少打一行,
  **整张表都被覆盖,而且没有「撤销」。**

  空跑一次:先用 where 1 = 0 验条件
  SQL> UPDATE classes SET teacher = '不会生效' WHERE 1 = 0
  影响 0 行

  **`where 1 = 0` 永远不成立,所以影响 0 行、什么都没改。**
  **它的用处是「先试一次,看条件能匹配几行」**——
  **把 `SET` 后面写成同一个值,跑一遍看影响行数,数字对了再把真正的 `SET` 换上去。**
  这个习惯能挡掉大半事故。

  动手之前先备份
  **最稳的做法是先 `CREATE TABLE 备份 AS SELECT * FROM 原表`**,
  **改坏了还能从备份里捞回来。** **第 15 章讲备份时会细讲。**

  SQL> CREATE TABLE classes_bak AS SELECT * FROM classes
  完成

  SQL> SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name
  name
  -------------
  classes
  classes_bak
  goods
  order_detail
  orders
  scores
  students
  (7 行)

  **多出一张 `classes_bak`,内容和 `classes` 当时一模一样。**
  **注意 `AS SELECT` 只复制数据,不复制索引和约束**,作为临时备份够用,当正式备份还不够。

  多条语句要一起成功:事务
  **转账这种操作要改两张表**:A 减 100、B 加 100。
  **如果第一条成功、第二条失败,钱就凭空消失了。**
  **事务(`begin` / `commit` / `rollback`)解决的就是这件事**:
  **要么全成,要么全不成。** **第 18 章专讲,这里先知道有这件武器。**

第一段改一行。 二班老师从「孔老师」变成「孔老师(代)」,影响 1 行。 第二段不写 where。 影响 3 行,三行全变「临时」——这就是事故的现场。 第三段空跑。 where 1 = 0 影响 0 行,什么都没改。 第四段备份。 多出一张 classes_bak, CREATE TABLE … AS SELECT 只复制数据,不复制索引和约束。 第五段没有 SQL,讲的是事务——begin/commit/rollback。

30 秒实验

  1. UPDATE classes SET teacher = 'x' WHERE id = 99 会显示影响几行?
  2. CREATE TABLE bak AS SELECT * FROM classes 之后,bak 上有主键吗?
  3. 为什么「影响 0 行」不等于「语句失败」?

常见误区

  1. update/delete 写完不检查 where。 少打一行就是全表,而且没有撤销。
  2. 把「影响 0 行」当成「出错了」。 它是「条件没匹配上」,语句本身是成功的, 该去查条件而不是查语法。
  3. 改完不回读。 影响 1 行不代表改对了,可能改的是另一行。改完再 select 一次确认。
自测三问(点开对答案) 1. `select` 和 `update` 最根本的区别是什么? —— `select` 只读,`update` 会改数据;改了没有撤销,只能靠事先备份或事务回滚。 2. 「影响 0 行」说明语句失败了吗? —— 没有失败,是 `where` 一行都没匹配上。该去查条件,不是查语法。 3. 改数据前有哪两个保命习惯? —— 先把 `where` 拿去做 `select` 确认范围;用 `where 1 = 0` 空跑一次提前发现写法错误。 另加一条:先备份。

三类语句里最安全的是「增」——下一篇 insert,四种写法与两种冲突处理。

相关笔记