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 秒实验
UPDATE classes SET teacher = 'x' WHERE id = 99会显示影响几行?CREATE TABLE bak AS SELECT * FROM classes之后,bak上有主键吗?- 为什么「影响 0 行」不等于「语句失败」?
常见误区
update/delete写完不检查where。 少打一行就是全表,而且没有撤销。- 把「影响 0 行」当成「出错了」。 它是「条件没匹配上」,语句本身是成功的, 该去查条件而不是查语法。
- 改完不回读。 影响 1 行不代表改对了,可能改的是另一行。改完再
select一次确认。
自测三问(点开对答案)
1. `select` 和 `update` 最根本的区别是什么? —— `select` 只读,`update` 会改数据;改了没有撤销,只能靠事先备份或事务回滚。 2. 「影响 0 行」说明语句失败了吗? —— 没有失败,是 `where` 一行都没匹配上。该去查条件,不是查语法。 3. 改数据前有哪两个保命习惯? —— 先把 `where` 拿去做 `select` 确认范围;用 `where 1 = 0` 空跑一次提前发现写法错误。 另加一条:先备份。三类语句里最安全的是「增」——下一篇 insert,四种写法与两种冲突处理。
- ☐ (本篇完,下一篇 7.2 插入数据:insert)