此页面为机器翻译。请阅读英文原文。 English

IBSurgeon 文库

视图(InterBase 和 Firebird)

Alexey Kovyazin,最后更新于2012年4月13日

熟悉SQL语言的人不需要对此主题进行详细解释,但为了保持叙述的连贯性,我们将简要介绍视图的定义。

视图(VIEW)是基于对普通表的查询而创建的虚拟表。视图以查询的形式实现,存储在服务器上,每次引用视图时都会执行该查询。

让我们考虑使用视图的不同变体。视图能够创建数据结构层次,允许将数据存储的实现与其类型分离。例如,我们可以创建一个视图,从多个表中选取数据。如果客户端使用此视图而不是直接引用底层表,数据库开发人员将能够更改视图底层的查询、修改它(例如,进行优化),而客户端不会注意到任何变化–对他来说,这仍然是同一个视图。除了将数据存储的实现与用户隔离之外,视图还允许以更方便、更简单的方式组织数据。当数据库中的表数量足够大且它们之间的相互关系变得复杂时,就会出现数据结构“简化”的问题。视图允许消除(或相反,添加)特定数据库客户端不需要(或需要)的部分数据。

此外,视图允许更简单地组织InterBase数据库中的安全性。某些用户可以只有读取/更新视图中数据的权限,但对视图底层的表没有权限(甚至不知道它们的存在)!有关InterBase安全性的更多详细信息,请参阅“InterBase中的安全性:用户、其功能和权限”一章(第4部分)。

用于处理视图的DDL语法

现在我们将考虑由DDL(数据定义语言–SQL子集,参见术语表)定义的创建和删除视图的命令。为了在InterBase中创建视图,我们应该使用以下语法的语句:

CREATE VIEW viewname [(view_column[, view_column…])] AS [WITH CHECK OPTION];

这里viewname是视图的名称,必须在数据库内唯一,然后是一组并非总是必需的字段名称,这些字段包含在视图中:[(view_column [, view_column …])]。定义选择视图中包含的数据的语句是必不可少的。我们将在“可修改视图”部分稍后讨论可选参数WITH CHECK OPTION。

要修改视图,我们必须重新创建它,即删除后再创建。删除视图时,还必须删除所有依赖对象–触发器、存储过程和其他视图。这是使用视图的主要不便之处之一:必须重新创建使用该视图的对象树(有一些实用工具可以让我们更轻松地完成此操作,例如IBAlterView,参见“管理员和InterBase设计器工具”应用程序)。如果我们想删除视图,应使用以下DDL命令:

DROP VIEW viewname;

视图示例

以下是一个简单视图的示例:

CREATE VIEW MyView AS SELECT NAME, PRICE_1 FROM Table_example;

在此示例中,我们基于对Table_example表的查询创建了一个视图,该表已在“表。主键和生成器”一章中讨论过。在这种情况下,视图将由两个字段组成–NAME和PRICE_1,它们将从Table_example表中无条件地选取,即视图MyView中的记录数将等于Table_example中的记录数。然而,视图并不总是如此简单。它们可以基于多个表的数据,甚至可以基于其他视图。此外,视图可以包含基于不同表达式(包括聚合函数)获得的数据。为了更详细地考虑此视图应用的使用,让我们创建两个通过一对多关系(通常称为主从关系)连接的表。以下是创建这些表的DDL脚本:

/\* Table: WISEMEN */

CREATE TABLE WISEMEN ( ID_WISEMAN INTEGER NOT NULL, WISEMAN_NAME VARCHAR(80));

/\* Primary keys definition */

ALTER TABLE WISEMEN ADD CONSTRAINT PK_WISEMEN PRIMARY KEY (ID_WISEMAN);

/\* Table: WISEBOOK */

CREATE TABLE WISEBOOK ( ID_BOOK INTEGER NOT NULL, ID_WISEMAN INTEGER, BOOK VARCHAR(80));

/\* Primary keys definition */

ALTER TABLE WISEBOOK ADD CONSTRAINT PK_WISEBOOK PRIMARY KEY (ID_BOOK);

/\* Foreign keys definition */

ALTER TABLE WISEBOOK ADD CONSTRAINT FK_WISEBOOK FOREIGN KEY (ID_WISEMAN) REFERENCES WISEMEN (ID_WISEMAN);

因此,我们创建了两个表–WISEMEN和WISEBOOK,通过外键约束(FOREIGN KEY)以主从关系连接。假设这些表将存储关于中国古代圣贤及其著作的信息。现在我们可以基于这些表创建几个视图。例如,让我们创建一个视图,显示每位圣贤有多少部著作:

CREATE VIEW WiseBookCount (WISEMAN, HOW_WISEBOOKS) AS SELECT M.WISEMAN_NAME, COUNT(B.BOOK) FROM WISEMEN M, WISEBOOK B WHERE (M.ID_WISEMAN = B.ID_WISEMAN) GROUP BY M.WISEMAN_NAME

请注意,当使用任何计算表达式(如聚合函数COUNT ()、SUM ()、MAX ()等)时,必须使用明确的视图字段名称,即为查询返回的所有字段命名。从这个示例可以看出,这些名称不必与查询字段的名称一致,但它们的数量必须与查询返回的字段数量一致。查询返回的字段与视图字段的对应关系按序号确定–查询的第一个字段对应视图的第一个字段,第二个对应第二个,依此类推。

如果我们想知道哪位圣贤写的书最多呢?我们将尝试在视图底层的查询中添加排序表达式–ORDER BY。然而,这个尝试将不会成功:在视图中不允许使用ORDER BY排序,当尝试创建包含ORDER BY的查询的视图时,将出现错误。如果我们想对视图返回的结果进行排序,就必须在客户端进行:

SELECT * FROM WiseBookCount ORDER BY HOW_WISEBOOKS

执行此SQL查询将得到期望的结果。除了在视图中使用ORDER BY表达式的限制外,我们也不能将执行存储过程得到的数据集用作数据源(参见下面的“存储过程”一章)。

也许,值得再举一个说明视图应用的示例。假设我们必须输出名字以字母“K”开头的圣贤列表。在这种情况下,我们将使用带条件的视图:

CREATE VIEW WiseMen2 (WISEMAN) AS SELECT M.WISEMAN_NAME FROM WISEMEN M WHERE M.WISEMAN_NAME LIKE ‘K%’

因此,很容易创建视图,它们扮演不断更新的数据提供者的角色,根据特定条件从数据库中选取数据。

可修改视图

我们上面提到过,有创建可修改数据视图的能力。确实如此–不仅可以读取视图中的数据,还可以修改它们!

有两种方法可以使视图可修改。第一种方法适用于视图基于单个表(或其他可修改视图)创建的情况,并且该表的所有列必须允许NULL值。此外,视图所基于的查询不能包含子查询、聚合函数、UDF、存储过程、DISTINCT和HAVING语句。如果满足所有这些条件,视图将自动变为可修改的,即我们可以对其执行DELETE、INSERT和UPDATE查询,这些查询将修改源表中的数据。

条件列表相当可观,极大地限制了此类可修改视图的应用,因此它们很少被使用。

为了创建一个违反上述任何条件的修改视图,需要应用触发器机制。有关触发器的更多详细信息,请参阅“触发器”章节(第1部分)。现在我们只考虑在VIEW中组织数据修改的一般原则。

为了使用触发器实现可更新的视图,必须完成以下操作。为给定的视图创建3个触发器,对应事件:BEFORE DELETE、BEFORE UPDATE和BEFORE INSERT。在这些触发器中描述在删除、更新和插入时应对数据执行的操作。

然后,我们应该在修改查询中使用给定的视图–DELETE、INSERT或UPDATE。当InterBase收到此查询时,它将检查该视图是否存在相应的触发器,即BEFORE DELETE/INSERT/UPDATE。如果存在可执行操作的触发器,InterBase将调用它来修改视图底层表中的真实数据(尽管也可以是其他数据–这些触发器没有文本限制),然后重新读取被修改的字符串(或字符串组)。

因此,可以实现视图中复杂的数据更新链。

在创建视图的语法描述中提到了WITH CHECK OPTION选项。如果在创建修改视图时设置了此选项,则插入或修改到此视图中的每个数据字符串都将根据进入视图的条件进行检查。可以这样解释:如果用户插入的新记录或作为更新现有记录的结果而获得的记录不满足作为VIEW数据提供者的查询条件,则此记录的插入将被取消并产生错误。

结论

尽管创建和使用视图看似简单,但它们为改善数据库中的数据组织提供了强大的能力,并允许创建数据组织的层次结构。

一些数据库应用程序设计者在工作中经常使用视图,而另一些则避免使用视图,理由是视图的修改复杂,并倾向于保持数据库方案尽可能简单高效。如何在工作中应用视图取决于您自己。最重要的是记住视图这样强大工具的存在,并知道如何使用它。