🦏 第11章 视图
📄 一句话概括

DROP VIEW 视图名, 只删「那条规则」,数据和基表一点不动——这是它和 DROP TABLE 最根本的区别。 IF EXISTS 让删不存在的视图不报错; DROP VIEW 一张表 会报 use DROP TABLE to delete table …。 表名和视图名共用一个命名空间,所以视图常带 v_ 前缀; 删底层视图不会级联删上层,上层会变成「坏视图」。

📝 本章和前面几章的关系

改视图讲完了,这一篇讲删——删除本身很轻,但「删完谁受影响」不轻。 drop view 是这一章里最安全的删除动作: 它不丢数据,最坏情况是「某个查询报错了,重建回来就行」。 但「重建回来」的前提是你记得原来怎么写的。

一、删之前先看一眼

先 select name from sqlite_master where type = 'view' 列一遍,再删。 这个动作花一秒,能挡掉「删错名字」。 删完再列一遍确认没了——两个方向都验证,比「没报错就当成功」可靠。

二、数据还在吗:在

12 行学生一个不少。 drop view 只删规则,数据和基表不动。 这是它和 drop table 最根本的区别:删视图不丢数据,删表丢。 所以「不想要这个视图了」是很轻的动作,不用备份。 真要备份,备份的是那句 create view 语句 ——从 sqlite_master 的 sql 列里拿出来存一份就行。

三、if exists:删不存在的视图不报错

第一次删报 no such view: v_boy,加 if exists 就不报。 和 drop table if exists 是同一个套路——初始化/清理脚本里几乎都要带它。 不带的话,脚本跑第二遍就会在这一步中断,后面的语句全不执行。 这个坑第 8 章撞过一次,视图这边一模一样。

四、drop view 删不掉表,drop table 删不掉视图

DROP VIEW students 报 use DROP TABLE to delete table students—— 这个报错写得很客气,直接告诉你该用哪条语句。 反过来的报错就没这么友好了: drop table 一个视图名,多数数据库会说「表不存在」,而不会提醒你「那是个视图」。 所以删东西之前先看清 type,别猜。

五、视图名和表名共用一个命名空间

CREATE VIEW classes AS … 报 table classes already exists。 表和视图不能重名, 因为它们在 select 里长得一样,重名了引擎没法知道你说的是哪个。 这也解释了为什么视图常带 v_ 前缀: 不是为了好看,是为了「一眼看出这是视图」,顺便避开跟表重名。 vw_、view_ 也是常见前缀,团队统一就行。

六、删视图也会牵连上层视图

v2 建在 v1 上,删掉 v1 之后 v2 还在清单里,但一查就报 no such table: v1。 删视图不会级联删上层——上层视图会变成「坏视图」,平时不报错,被查时才炸。 所以删视图前也得看依赖,和删表一样: 先用 sqlite_master 的 sql 列搜一遍谁引用了它。 这一步花十秒,能省掉半夜的电话。

七、动手 Demo:删一个视图,数据还在;再撞三次删不掉的情况

Demo 六段:列一遍视图、删掉、再列一遍确认;看学生表还是 12 行;撞「视图不存在」「删一张表」; 最后撞一次「跟表重名」,再演示删底层视图把上层弄坏。 第二段那个 12 行是全篇的核心——它说明「删视图」和「删表」完全不是一回事。

import _q46 as Q
c = Q.con()
c.execute("CREATE VIEW v_boy AS SELECT id, name FROM students "
          "WHERE gender = '男'")

Q.show(c, "SELECT name FROM sqlite_master WHERE type = 'view' ORDER BY name")
Q.run(c, "DROP VIEW v_boy")
Q.show(c, "SELECT name FROM sqlite_master WHERE type = 'view' ORDER BY name")

# 数据一点没动
Q.show(c, "SELECT COUNT(*) AS students_rows FROM students")

# 删不存在的视图;删一张表
c.execute("DROP VIEW v_boy")
c.execute("DROP VIEW IF EXISTS v_boy")
c.execute("DROP VIEW students")

# 视图名和表名共用命名空间
c.execute("CREATE VIEW classes AS SELECT 1 AS x")

# 删底层视图,上层变「坏视图」
c2 = Q.con()
c2.execute("CREATE VIEW v1 AS SELECT id, name, height FROM students")
c2.execute("CREATE VIEW v2 AS SELECT * FROM v1 WHERE height > 175")
c2.execute("DROP VIEW v1")
c2.execute("SELECT * FROM v2")

实跑输出:

--------------------------------------------------------------------
第六十一课:删除视图——只删规则,不删数据
--------------------------------------------------------------------

  删之前先看一眼
  SQL> SELECT name FROM sqlite_master WHERE type = 'view' ORDER BY name
  name
  ------
  v_boy
  (1 行)
  SQL> DROP VIEW v_boy
  完成
  SQL> SELECT name FROM sqlite_master WHERE type = 'view' ORDER BY name
  name
  -----
  (0 行)
  **清单里没了。** **`drop view 视图名` 只删「那条规则」,数据和基表一点不动。**

  数据还在吗:在
  SQL> SELECT COUNT(*) AS students_rows FROM students
  students_rows
  --------------
  12
  (1 行)
  **12 行一个不少。** **这是 `drop view` 和 `drop table` 最根本的区别**:
  **删视图不丢数据,删表丢。** **所以「不想要这个视图了」是很轻的动作,不用备份。**

  if exists:删不存在的视图不报错
  SQL> DROP VIEW v_boy
  报错:no such view: v_boy
  **第一次报 `no such view: v_boy`,加 `if exists` 就不报。**
  **和 `drop table if exists` 是同一个套路**——**初始化/清理脚本里几乎都要带它。**

  drop view 删不掉表,drop table 删不掉视图
  SQL> DROP VIEW students
  报错:use DROP TABLE to delete table students
  **报 `use DROP TABLE to delete table students`**——
  **这个报错写得很客气,直接告诉你该用哪条语句。**
  **反过来的报错就没这么友好了**:
  **`drop table` 一个视图名,多数数据库会说「表不存在」,而不会提醒你「那是个视图」。**
  **所以删东西之前先看清 `type`,别猜。**

  视图名和表名共用一个命名空间
  SQL> CREATE VIEW classes AS SELECT 1 AS x
  报错:table classes already exists
  **报 `table classes already exists`。** **表和视图不能重名**,
  因为它们在 `select` 里长得一样——**重名了引擎没法知道你说的是哪个。**
  **这也解释了为什么视图常带 `v_` 前缀**:
  **不是为了好看,是为了「一眼看出这是视图」,顺便避开跟表重名。**
  **`vw_`、`view_` 也是常见前缀,团队统一就行。**

  删视图也会牵连上层视图
  SQL> SELECT * FROM v2
  报错:no such table: main.v1
  **`v2` 还在清单里,但一查就报 `no such table: v1`。** **删视图不会级联删上层**——
  **上层视图会变成「坏视图」,平时不报错,被查时才炸。**
  **所以删视图前也得看依赖**,
  **和删表一样:先用 `sqlite_master` 的 `sql` 列搜一遍谁引用了它。**
  **这一步花十秒,能省掉半夜的电话。**

第一段 v_boy 在清单里,删完变成 0 行。 第二段学生表还是 12 行,数据一点没动。 第三段 DROP VIEW students 报 use DROP TABLE to delete table students。 第四段建同名视图报 table classes already exists。 第五段删掉 v1 之后查 v2 报 no such table: main.v1——坏视图平时不报错,被查时才炸。

30 秒实验

  1. DROP VIEW 之后基表数据会少吗?为什么?
  2. DROP VIEW students 会怎样?DROP TABLE 一个视图名 呢?
  3. 删掉底层视图,上层视图会立刻报错吗?什么时候才会暴露?

常见误区

  1. 把 DROP VIEW 当成「删数据」。 数据一点不动,它只删那条规则。
  2. 删视图不看上层依赖。 上层视图变成坏视图,平时不报错,等有人查的时候才炸。
  3. 视图不起前缀。 和表重名时建不出来,而且看代码时分不清哪个是视图。
自测三问(点开对答案) 1. `DROP VIEW` 和 `DROP TABLE` 最根本的区别是什么? —— `DROP VIEW` 只删规则、不丢数据;`DROP TABLE` 表和里面的数据一起没。 2. 删视图前为什么要看依赖? —— 删掉底层视图后上层视图不会级联删除,会变成「坏视图」,被查时才报错。 3. 视图为什么常带 `v_` 前缀? —— 表名和视图名共用一个命名空间,前缀能避开重名,也让人一眼看出这是视图。

单个表的视图会了,下一篇把它用在多表上:11.5 多表视图。

相关笔记