UPDATE 改格子,DELETE 拆整行,两条都以 WHERE 为命门。这一章的重点不是语法, 而是「怎么不闯祸」。 Demo 里带 WHERE 的更新影响 1 行, 不带 WHERE 的影响 5 行——五个客户的邮箱全被同一个值覆盖; DELETE 同理,带条件删一行,不带条件清空整表。
上一章是「往里加」,这一章是「改已有的、删不要的」。 这两条语句是全书最危险的两条,因为它们默认立刻生效、默认动全部行、 而且多数引擎不问你「确定吗」。
一、更新数据:UPDATE
UPDATE 表 SET 列 = 值 WHERE 条件:满足条件的行,把那一列改掉。
SET 可以一次改多列,用逗号隔开。
不带 WHERE 就是对每一行执行——这不是「没生效」,是「全都生效了」。
教材特意用大写强调这一点,因为它是新手最常见的一次性事故。
值是 NULL 就是清空格子,行还在。
这跟 DELETE 完全不同:一个是把格子擦干净,一个是把整行拆掉。
改多列要写在同一条 SET 里:分两条发中间会有一个「改了一半」的瞬间,
别人这时读到就是脏数据;而且两条之间出错,就只有一半改了。
二、删除数据:DELETE
DELETE FROM 表 WHERE 条件:删掉满足条件的行。表结构、索引、别的行都不受影响。
不带 WHERE 就是清空整表,但表还在——这一点和 DROP TABLE 不同:
DROP 连结构一起删,DELETE 只删数据。
DELETE 不会重置自增计数器(有些引擎会,SQLite 默认不清)。
所以清空后新插的行,编号接着往下走,不是从 1 开始。
想清空整表又想快,很多引擎给了 TRUNCATE(MySQL 有,SQLite 没有),
它比 DELETE 快得多,因为它不逐行删、也不写日志——同时也更不可恢复。
三、更新和删除的指导原则
第一条:永远别执行不带 WHERE 的 UPDATE 与 DELETE,除非你就是要动全表, 而且确认过全表就是你想要的范围。 第二条:先用 SELECT 验一遍。 同样的 WHERE 跑 SELECT, 行数对了、内容对了,再把 SELECT 换成 UPDATE 或 DELETE。 这个习惯能省掉绝大多数事故。 第三条:能上事务就上事务(第 26 章)。 改完先不提交,用 SELECT 验一遍,没问题再 COMMIT,不对就 ROLLBACK。 还有一条实操经验:改之前备份。 本课的内存库一关就没,真实环境没有这个后悔药, 所以「先备份、再改、改完核对」是标准三步。
四、小结
教材小结: UPDATE 改行、DELETE 删行,两者都必须带 WHERE,改之前先用 SELECT 验证,能上事务就上事务。 本课补三条:一是 SET NULL 与 DELETE 是两件事;二是 DELETE 不重置自增; 三是没有 WHERE 的语句是事故,不是捷径。
五、动手 Demo:一行与五行,就差一个 WHERE
Demo 七段:先看清要改哪行,再带条件改一行,然后故意不带条件改五行; 接着改多列、改 NULL、删一行、清空整表。 每段都看「影响 N 行」那句话——它就是这次动手的范围。
import sqlite3
con = sqlite3.connect(":memory:")
# 第一步永远是看清楚:要改哪几行
con.execute("SELECT cust_id, cust_name, cust_email FROM customers "
"WHERE cust_id = 10005")
# UPDATE 一行:WHERE 是命门
con.execute("UPDATE customers SET cust_email = '[email protected]' "
"WHERE cust_id = 10005")
# 不带 WHERE:五行全改,这是事故
con.execute("UPDATE customers SET cust_email = '[email protected]'")
# 改多列:一条 SET 搞定
con.execute("UPDATE customers SET cust_email = '[email protected]', "
"cust_contact = 'E Fudd Sr.' WHERE cust_id = 10005")
# 把值改成 NULL:清空格子,不删行
con.execute("UPDATE customers SET cust_email = NULL WHERE cust_id = 10005")
# DELETE 带 WHERE:删一行
con.execute("DELETE FROM customers WHERE cust_id = 10002")
# DELETE 不带 WHERE:清空整表,表结构还在
con.execute("DELETE FROM customers")
实跑输出:
--------------------------------------------------------------------
第二十课:更新和删除数据
--------------------------------------------------------------------
【一】改之前先看清楚:要改哪几行
SQL> SELECT cust_id, cust_name, cust_email FROM customers WHERE cust_id = 10005
cust_id cust_name cust_email
-------------------------------------
10005 E Fudd NULL
(1 行)
**E Fudd 没有邮箱。** 要给他补一个,先确认这一行是不是你要改的那行。
【二】UPDATE 一行:WHERE 是命门
SQL> UPDATE customers SET cust_email = '[email protected]' WHERE cust_id = 10005
影响 1 行
SQL> SELECT cust_id, cust_name, cust_email FROM customers WHERE cust_id = 10005
cust_id cust_name cust_email
--------------------------------------------
10005 E Fudd [email protected]
(1 行)
**影响 1 行,改动只有那一行。** 教材反复强调:**UPDATE 一定要带 WHERE。**
【三】不带 WHERE 会怎样:全表都被改
SQL> UPDATE customers SET cust_email = '[email protected]'
影响 5 行
SQL> SELECT cust_id, cust_email FROM customers ORDER BY cust_id
cust_id cust_email
--------------------------
10001 [email protected]
10002 [email protected]
10003 [email protected]
10004 [email protected]
10005 [email protected]
(5 行)
**影响 5 行,五个客户的邮箱全被覆盖。** 这不是更新,是事故。
**教材的原话是「不加 WHERE 就是对每一行执行」**,**而且它不会问你一句「确定吗」。**
**这条事故有个标准防线:先写 SELECT,确认行数对了,再把 SELECT 改成 UPDATE。**
【四】改多列:一条 SET 搞定
SQL> UPDATE customers SET cust_email = '[email protected]',
cust_contact = 'E Fudd Sr.' WHERE cust_id = 10005
影响 1 行
SQL> SELECT cust_id, cust_contact, cust_email FROM customers WHERE cust_id = 10005
cust_id cust_contact cust_email
---------------------------------------------
10005 E Fudd Sr. [email protected]
(1 行)
**多列用逗号隔开,一条语句改完。** 分两条发也能到同样结果,
**但中间会有一个「改了一半」的状态**——别人这时候读到就是脏的。
【五】把值改成 NULL:删掉内容,不删行
SQL> UPDATE customers SET cust_email = NULL WHERE cust_id = 10005
影响 1 行
SQL> SELECT cust_id, cust_name, cust_email FROM customers WHERE cust_id = 10005
cust_id cust_name cust_email
-------------------------------------
10005 E Fudd NULL
(1 行)
**行还在,只是那一格空了。** 这和 DELETE 是两件事:**一个是清空格子,一个是拆掉整行。**
【六】DELETE:删行,WHERE 依然是命门
SQL> DELETE FROM customers WHERE cust_id = 10002
影响 1 行
SQL> SELECT cust_id, cust_name FROM customers ORDER BY cust_id
cust_id cust_name
---------------------------
10001 Coyote Inc.
10003 Wascals
10004 Yosemite Place
10005 E Fudd
(4 行)
**Mouse House 没了,剩四行。** 表结构、索引、别的行都不受影响。
**上面已经删掉一行,为了看得清楚,这一段换一条干净连接:库里还是五行。**
SQL> DELETE FROM customers
影响 5 行
SQL> SELECT COUNT(*) AS n FROM customers
n
--
0
(1 行)
**不带 WHERE 就是清空整张表:影响 5 行。**
**注意它比 DROP TABLE 温和**:表还在,只是没数据了。 **想要「删表连结构一起」才用 DROP。**
【七】三条指导原则(教材原话的意思)
**第一,永远别执行不带 WHERE 的 UPDATE 与 DELETE**,除非你真的要动全表。
**第二,先用 SELECT 验一遍**:同样的 WHERE 条件跑 SELECT,行数对了再动手。
**第三,能上事务就上事务**(第 26 章):改完确认没问题再提交,不对就回滚。
**本沙箱的内存库一关就没了,真实环境可没有这个后悔药。**
第一段先查。 E Fudd 的邮箱是 NULL,确认这一行就是要改的那行。 第二段带 WHERE 改。 影响 1 行,这就是正确姿势。 第三段不带 WHERE。 影响 5 行,五个邮箱全变成 [email protected]。 第四段改多列。 一条 SET 同时改联系人与邮箱,影响 1 行。 第五段改 NULL。 行还在,只是那一格空了。 第六段删一行。 Mouse House 没了,剩四行,表结构没事。 第七段清空。 换一条干净连接,五行全删,COUNT 给 0,表还在。
30 秒实验
- 把第三段的 WHERE 补成
WHERE cust_id = 10001,影响几行? - 用同样的 WHERE 先跑 SELECT 再跑 DELETE,两次的行数应该一样吗?
- (先想再跑)清空 customers 之后再插一行,cust_id 会是 1 还是 10006?
常见误区
- 写 UPDATE 忘了 WHERE。全表被改成同一个值,而且立刻生效。
- 以为 DELETE 会连表一起删。它只删数据;连结构删是 DROP TABLE。
- 删完以为自增编号会归零。多数引擎不清计数器,新行编号接着往下走。
自测三问(点开对答案)
1. UPDATE 和 DELETE 最容易犯的错是什么? —— 漏写 WHERE:UPDATE 会把同一列值覆盖全表,DELETE 会清空整表,都不报错、都立刻生效。 2. `SET 列 = NULL` 和 `DELETE` 有什么区别? —— 前者只清空格子,行还在;后者删掉整行,连别的列一起没了。 3. 动数据之前的标准三步是什么? —— 先用同样的 WHERE 跑 SELECT 验证行数,再执行改/删,最后核对;能上事务就放进事务里。数据能加、能改、能删了,但表本身还是别人建好的。 下一章自己动手建表、加列、删表、改名。
- ☐ (本章完,下一章 第21章 创建和操纵表)