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

视图记在 sqlite_master 里,type 是 view,和表混在同一张清单里,靠 type 区分。 sql 那一列原样存着建视图时写的那句话; MySQL 那边是 SHOW CREATE VIEW,还能查 information_schema.views。 PRAGMA table_info 对视图也能用,但 pk、dflt_value 全是 0—— 视图没有主键、没有默认值,别拿它当表结构用。

📝 本章和前面几章的关系

上一篇建视图,这一篇学「查视图」——查的是「有哪些视图」和「视图怎么定义的」。 这件事在维护时比建视图更常用:接手一个老库,第一件事就是列出所有视图看一遍, 因为视图里往往藏着最复杂的业务逻辑。

一、视图记在 sqlite_master 里,type 是 view

where type in ('table', 'view') 把表和视图一起列出来, 靠 type 区分。 Demo 里六张表加一个视图,一共七行。 所以「这个库里有哪些视图」就是加一句 where type = 'view'。 对使用者来说,视图和表在 select 里长得一样,只有查元数据时才需要区分。

二、看视图的定义:就是那句 SQL

sql 那一列原样存着建视图时写的那句话。 拿它出来看,就知道这个视图到底在算什么。 MySQL 那边是 SHOW CREATE VIEW 视图名,给的信息更多(字符集、检查选项、定义者)。 也能查 information_schema.views, 有 VIEW_DEFINITION、CHECK_OPTION、IS_UPDATABLE 这些列。 最后那个 IS_UPDATABLE 特别实用: 它直接告诉你「这个视图能不能写」,不用自己去判断有没有聚合、union。 本沙箱没有这个视图,只能靠读定义自己看。

三、看视图的列:PRAGMA 也能用

视图的列信息也能查出来,但注意 pk 和 dflt_value 全是 0——视图没有主键、没有默认值, 它只是「查询结果的形状」。 notnull 也不可靠: 视图里一列是否非空,取决于查询怎么写,而不是基表的约束。 所以别拿视图的 PRAGMA 当表结构用。 真正要看的还是基表的 PRAGMA。 视图的 PRAGMA 只用来确认「列名对不对、列数对不对」, 这两个信息它是准的。

四、视图的依赖:改基表前先看谁在用它

拿视图定义的文本去 like '%students%',能找到引用某张表的视图。 这是土办法,但比「什么都不查就改」强得多。 它很粗糙:改个表名、加个空格就匹配不上; 表名是另一个表名的子串时还会误报(比如 order 和 order_detail)。 真 MySQL 上可以查 information_schema.view_table_usage, 那是专门记录「视图用了哪些表」的,精确得多。 本沙箱只能靠文本匹配,所以要记得:视图依赖是隐式的,删表前必须人工确认。

五、动手 Demo:列出表和视图、看定义、看列、找依赖

Demo 四段:把表和视图一起列出来、取视图的定义、用 PRAGMA 看视图的列, 最后用 like 找「谁引用了 students」。 第四段那个 like 是这一篇最实用的技巧,虽然粗糙,但改表之前花十秒跑一遍,能挡掉很多事故。

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

# 表和视图混在一张清单里,靠 type 区分
Q.show(c, "SELECT type, name FROM sqlite_master "
          "WHERE type IN ('table', 'view') ORDER BY type, name")

# 视图的定义就是那句 SQL
Q.show(c, "SELECT sql FROM sqlite_master WHERE name = 'v_boy'")

# 视图的列信息
Q.show(c, "PRAGMA table_info(v_boy)")

# 谁在引用 students:拿定义文本去 like
Q.show(c, "SELECT name, sql FROM sqlite_master WHERE type = 'view' "
          "AND sql LIKE '%students%'")

实跑输出:

--------------------------------------------------------------------
第五十九课:查看视图——它也是系统表里的一条记录
--------------------------------------------------------------------

  视图记在 sqlite_master 里,type 是 view
  SQL> SELECT type, name FROM sqlite_master WHERE type IN ('table', 'view') ORDER BY type, name
  type      name
  -----------------------
  table     classes
  table     goods
  table     order_detail
  table     orders
  table     scores
  table     students
  view      v_boy
  (7 行)
  **表和视图混在一张清单里,靠 `type` 区分。**
  **所以「这个库里有哪些视图」就是加一句 `where type = 'view'`。**
  **注意六张样例表都在,但它们和视图平级**——
  **对使用者来说,视图和表在 `select` 里长得一样,只有查元数据时才需要区分。**

  看视图的定义:就是那句 SQL
  SQL> SELECT sql FROM sqlite_master WHERE name = 'v_boy'
  CREATE VIEW v_boy AS SELECT id, name, height FROM students WHERE gender = '男'

  **`sql` 那一列原样存着建视图时写的那句话。** **MySQL 那边是 `SHOW CREATE VIEW 视图名`**,
  给的信息更多(字符集、检查选项、定义者)。
  **`information_schema.views` 也能查**,
  **有 `VIEW_DEFINITION`、`CHECK_OPTION`、`IS_UPDATABLE` 这些列**——
  **最后那个能直接告诉你「这个视图能不能写」,很实用。**

  看视图的列:PRAGMA 也能用
  SQL> PRAGMA table_info(v_boy)
  cid     name       type        notnull     dflt_value     pk
  ---------------------------------------------------------------------
  0       id         INTEGER     0           NULL           0
  1       name       TEXT        0           NULL           0
  2       height     REAL        0           NULL           0
  (3 行)
  **视图的列信息也能查出来**,
  但**注意 `pk` 和 `dflt_value` 全是 0**——**视图没有主键、没有默认值**,它只是「查询结果的形状」。
  **`notnull` 也不可靠**:
  **视图里一列是否非空,取决于查询怎么写,而不是基表的约束。**
  **所以别拿视图的 `PRAGMA` 当表结构用。**

  视图的依赖:改基表前先看谁在用它
  SQL> SELECT name, sql FROM sqlite_master WHERE type = 'view' AND sql LIKE '%students%'
  name      sql
  -----------------------------------------------------------------------------------------
  v_boy     CREATE VIEW v_boy AS SELECT id, name, height FROM students WHERE gender = '男'
  (1 行)
  **这是找「谁引用了某张表」的土办法**:拿视图定义的文本去 `like` 一下。
  **它很粗糙**(**改个表名、加个空格就匹配不上**),
  **但比「什么都不查就改」强得多。** **真 MySQL 上可以查 `information_schema.view_table_usage`**,
  **那是专门记录「视图用了哪些表」的。**
  **本沙箱只能靠文本匹配,所以要记得:视图依赖是隐式的,删表前必须人工确认。**

第一段七行:六张表加一个 v_boy,type 列区分。 第二段给出完整的建视图语句,一字不差。 第三段 PRAGMA 三行,pk 和 dflt_value 全是 0。 第四段筛出 v_boy——它是唯一引用 students 的视图。

30 秒实验

  1. 怎么列出这个库里所有的视图?
  2. 视图的 PRAGMA table_info 里,pk 列为什么永远是 0?
  3. 要改基表结构,怎么先查出「哪些视图会受影响」?

常见误区

  1. 拿视图的 PRAGMA 当表结构用。 pk、dflt_value、notnull 都不可靠,要看结构得看基表。
  2. 以为改了视图就完事,不管谁在用。 视图藏起来的复杂度,改错了有一堆报表跟着崩。
  3. 用 like '%order%' 找依赖。 会连带匹配 order_detail,误报一堆, 该把表名带上下划线或者用元数据表查。
自测三问(点开对答案) 1. 怎么看出一个库里有哪些视图? —— 查 `sqlite_master` 加 `where type = 'view'`。 MySQL 用 `SHOW FULL TABLES WHERE Table_type = 'VIEW'`。 2. 视图的定义存在哪一列? —— `sqlite_master` 的 `sql` 列,原样存着建视图时写的那句语句。MySQL 用 `SHOW CREATE VIEW`。 3. 为什么视图的 `PRAGMA` 里 `pk` 永远是 0? —— 视图不是表,没有主键和默认值,它只是查询结果的形状。

会看了,接下来是「改」。下一篇 11.3 修改视图——两条路,这里都走不通。

相关笔记