知识卡片

SQL视图可更新性规则的复杂混乱及CHECK选项

操作参考卡

内容

针对[[视图更新失败的本质是违反黄金规则或赋值原理]]里”违反用户不知情约束” 这类问题,SQL提供了CHECK OPTION机制:给视图声明WITH CASCADED CHECK OPTION 后,任何对该视图的更新都必须符合视图定义表达式本身——否则会被拒绝,而不是 默默地把行写进底层基表却让它”从视图角度看不见”(这种默认行为本身就直接违反 赋值原理:用户认为自己插入了一行,但从视图的视角看这次插入其实什么都没 发生)。实践建议是只要视图被认定为可更新,就应该指定CASCADED(这是默认项, 不必显式写出);CASCADED的替代项LOCAL语义相当古怪,作者建议直接不用。但SQL 判定”一个视图是否可更新”的规则本身极其复杂、零散分布在标准各处,涉及大量 彼此关联的底层概念(可更新列、叶子表、query term等),书中举了一个反例说明 这套规则甚至可能不自洽——形式上通过所有条件判定为”可更新”的一个UNION ALL 视图,实际执行更新却明显不正确。SQL还进一步区分了可更新、潜在可更新、简单 可更新、可插入这4种细分状态(标准正式定义了这些术语却没有解释直觉含义), 大致规律是”可更新”对应UPDATE/DELETE、”可插入”对应INSERT,且一个视图除非 先是可更新的才可能可插入,但某些视图却允许DELETE却拒绝INSERT(或反过来), 导致DELETE和INSERT不再互为逆运算——这正是对[[互换性原理及其重要推论]]的 又一处具体违反。作为参照,一个SQL视图若满足以下全部条件则肯定可更新:定义 表达式是单一SELECT(不是UNION/INTERSECT/EXCEPT的组合);SELECT子句用ALL 而非DISTINCT;展开所有星号后SELECT项列表每项都是简单列名(可限定/可AS,且 每列至多出现一次);FROM子句形如FROM T[AS...]且T本身是可更新表;若有WHERE 子句则不包含对FROM里同一张表T的子查询;没有GROUP BY或HAVING。

参考来源

- 位置:《SQL与关系数据库理论——如何编写健壮的SQL代码》第9章"SQL与视图" 9.5.1节"CHECK选项"、9.5.2节"关于SQL的更多内容"(源文件:OEBPS/text00104.html) - 结论依据:原文明确"当且仅当对给定视图指定了WITH CASCADED CHECK OPTION 时,对该视图的更新都应符合该视图的定义表达式……SQL标准正式定义了这些 术语但是却没有给出对这些术语直观含义的说明……一些视图允许某些更新却拒绝 另外一些更新(例如,允许DELETE却拒绝INSERT)……可能因此会有DELETE和 INSERT不再互为逆运算的情况",并给出可更新性的具体判定条件清单。 - 原始内容:当且仅当对给定视图指定了WITH CASCADED CHECK OPTION时,对该 视图的更新都应符合该视图的定义表达式……一些视图允许某些更新却拒绝另外 一些更新……可能因此会有DELETE和INSERT不再互为逆运算的情况。