drop table 表名,
表和数据一起消失,索引、触发器也一起没。 没有撤销,也没有「回收站」。
if exists 让「删不存在的表」不报错,和建表时的 if not exists 正好配成一对。
有外键指着就删不掉(students 指着 classes,报 FOREIGN KEY constraint failed)。
更稳的做法是改名加日期、观察一周再删。
第 8.1 篇说「先改名、后删除」,这一篇就是它的落地。 删表是这一章唯一一个「完全不可逆」的动作——改表还能重建,删表连表都没了。 所以这一篇的一半篇幅在讲「怎么不删」。
一、先列一遍表
删之前先 show tables 看一眼,是这一步的唯一保险。 Demo 里先列六张表,建一张 demo_tmp,
确认它真的多出来了。
名字打错一位,删掉的就是另一张。 这种事故听起来很低级,但真实发生过很多次——
尤其是 orders 和 order_detail、user 和 users 这种只差一两个字母的表名。
二、drop table
drop table demo_tmp,完成。 再查一次系统表,still_there 是 0——已经没了。
表和数据一起消失,索引、触发器也一起没。 没有撤销,也没有「回收站」。
备份是唯一的后悔药。
它和 delete from 表 差一个层级:
delete 删行、表还在;drop 把整个容器端走。 两个词只差两个字母,后果差一个量级。
三、if exists:删不存在的表不报错
同一句 drop table demo_tmp 再跑一遍,报 no such table: demo_tmp。
加 if exists 就不报:
「存在才删」,不存在就静默跳过。 和建表时的 if not exists 正好配成一对。
初始化/清理脚本里几乎都要带它,
否则脚本跑第二遍就会在「表不存在」这一步中断,后面的语句全不执行。
一个常被忽略的细节:if exists 只避免「不存在」这一种报错,
权限不够、被外键拦住,它一样报——它不是万能的兜底。
四、有外键指着,删不掉
DROP TABLE classes 报 FOREIGN KEY constraint failed。 因为 students 表里还有学生指着它。
MySQL 那边报 Cannot delete or update a parent row,理由一样。
这就是外键的价值:它不让你留下「指向不存在的班」的学生。
正确顺序是先删子表、再删父表:
先 drop table students、再 drop table classes。
但删之前要想清楚:那两个表的数据都不要了吗? 顺序对了不等于决定对了。
五、更稳的做法:改名 + 观察
ALTER TABLE classes RENAME TO classes_old_20261030,表还在,只是改了个带日期的名字。
业务立刻就不能用了——效果和删掉差不多,
但数据还在,随时能改回来。 观察一周没人喊,再 DROP。
这个习惯的价值在于:删表是不可逆的,改名是可逆的。
能先用可逆的方式验证,就别一上来用不可逆的。 这条原则不只适用于删表——改类型、改字符集、
换索引,都能先做一次「可逆版本」。
六、动手 Demo:删一张临时表,然后撞三次删不掉的情况
Demo 六段:先列一遍表、建一张临时表把它删掉,再撞「表不存在」「外键拦住」,最后用改名代替删除。 第三段和第四段都是「删不掉」——它们说明在真实库里,删除从来不是一个自由动作。
import _q46 as Q
c = Q.con()
# 删之前先列一遍
Q.show(c, "SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name")
Q.run(c, "CREATE TABLE demo_tmp (id INTEGER PRIMARY KEY)")
Q.run(c, "DROP TABLE demo_tmp")
# 表不存在时删会报错,IF EXISTS 不报
c.execute("DROP TABLE demo_tmp")
Q.run(c, "DROP TABLE IF EXISTS demo_tmp")
# 有外键指着,删不掉
c.execute("DROP TABLE classes")
# 更稳的做法:改名、观察、再删
Q.run(c, "ALTER TABLE classes RENAME TO classes_old_20261030")
实跑输出:
--------------------------------------------------------------------
第四十一课:删表——最该慢一步的动作
--------------------------------------------------------------------
先看清楚要删的是哪张
SQL> SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name
name
-------------
classes
goods
order_detail
orders
scores
students
(6 行)
SQL> CREATE TABLE demo_tmp (id INTEGER PRIMARY KEY)
完成
**多了一张 `demo_tmp`。** **删之前先列一遍表,是这一步的唯一保险**——
**名字打错一位,删掉的就是另一张。**
删掉它
SQL> DROP TABLE demo_tmp
完成
SQL> SELECT COUNT(*) AS still_there FROM sqlite_master
WHERE type = 'table' AND name = 'demo_tmp'
still_there
------------
0
(1 行)
**`drop table 表名`**,给 0 表示已经没了。
**表和数据一起消失,索引、触发器也一起没。** **没有撤销,也没有「回收站」。**
IF EXISTS:删不存在的表不报错
SQL> DROP TABLE demo_tmp
报错:no such table: demo_tmp
SQL> DROP TABLE IF EXISTS demo_tmp
完成
**第二句不报错。** **`IF EXISTS` 的意思是「存在才删」**,
**和建表时的 `IF NOT EXISTS` 正好配成一对。**
**初始化/清理脚本里几乎都要带它**,**否则脚本跑第二遍就会在「表不存在」这一步中断。**
有外键指着,删不掉
SQL> DROP TABLE classes
报错:FOREIGN KEY constraint failed
**`students` 还指着 `classes`,所以删不掉。**
**MySQL 那边报 `Cannot delete or update a parent row`,理由一样。**
**正确顺序是先删子表、再删父表**:
**先 `drop table students`、再 `drop table classes`。**
**但删之前要想清楚:那两个表的数据都不要了吗?**
更稳的做法:改名 + 观察
SQL> ALTER TABLE classes RENAME TO classes_old_20261030
完成
SQL> SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name
name
---------------------
classes_old_20261030
goods
order_detail
orders
scores
students
(6 行)
**表还在,只是改了个带日期的名字。** **业务立刻就不能用了——效果和删掉差不多**,
**但数据还在,随时能改回来。**
**观察一周没人喊,再 `DROP`。** **这个习惯的价值在于:删表是不可逆的,改名是可逆的。**
**能先用可逆的方式验证,就别一上来用不可逆的。**
第一段列六张表,建了 demo_tmp 之后变七张——这一步就是「确认要删的是哪张」。
第二段删掉它,查 sqlite_master 里 still_there 是 0。
第三段再删一次,报 no such table;if exists 版本不报。
第四段撞外键,classes 删不掉——students 还指着它。
第五段改名,classes_old_20261030 出现在表清单里,表还在、数据还在。
30 秒实验
DROP TABLE students能成功吗?为什么和DROP TABLE classes不一样?DROP TABLE IF EXISTS t在 t 不存在时会报错吗?如果权限不够呢?- 要给一张还在用的表「留后路」,比
drop更好的第一步是什么?
常见误区
- 删表前不列一遍表名。 名字打错一位删掉的是另一张,而且没有回收站。
- 以为
if exists能兜住所有报错。 它只管「表不存在」,权限不够、外键拦住照样报。 - 直接
drop父表。 有外键指着根本删不掉, 正确顺序是先删子表——但顺序对了要先想清楚数据要不要。
自测三问(点开对答案)
1. `drop table` 和 `delete from 表` 差在哪? —— `delete` 删行,表还在;`drop` 把表连同数据、索引、触发器一起删掉。 2. 为什么 `DROP TABLE classes` 会失败?怎么才能删掉? —— `students` 表有外键指向它。要先删 `students` 或先清空它的引用,再删 `classes`。 3. 为什么「改名 + 观察一周」比直接删更稳? —— 改名是可逆的,删表不可逆。业务出问题时一个 `RENAME` 就能改回来,删了只能靠备份。第 8 章到这儿完了:建、看、改、复制、删,五件事都会了。 下一篇进第 9 章——列的属性,把这章只用了一下的那五个约束讲透。
- ☐ (本篇完,下一篇 9.1 列的属性简介)