1.6 视图选项
当你创建或修改视图时,可以指定一些选项,这些选项用于控制视图的行为和功能。ENCRYPTION、SCHEMABINDING和 VIEW_METADATA选项在视图头指定,CHECK OPTION选项则在查询之后指定。
ENCRYPTION
ENCRYPTION选项可用于视图、UDF、存储过程和触发器。如果未指定ENCRYPTION选项,SQL Server在sys.sql_modules(在SQL Server 2000中是syscomments)中以纯文本的形式保存用于定义对象/程序主体的语句。如果指定ENCRYPTION选项,对象的文本将会被混淆,但不要依赖这个选项作为加密机制来保护你的智力成果。人们已经发现了对使用ENCRYPTION选项创建的对象文本进行解密的方法。甚至在SQL Server 2005中,创建对象的文本对于特权用户也是可以访问的,他们通过专用管理员连接(dedicated administrator connection,DAC)可以直接访问数据库文件,或者使用调试器对内存进行访问。关于ENCRYPTION选项的更详细的信息,请参考联机丛书。
SCHEMABINDING
SCHEMABINDING选项把视图或UDF的架构绑定到基对象的架构。如果你使用SCHEMABINDING选项创建视图,SQL Server将不允许删除基对象或修改被引用的列。这个选项对于定义视图的查询有两个语法要求:所有对象必须使用由两部分构成的名称(例如,应该使用dbo.Orders,不能是Orders),而且不能在SELECT列表中使用*,所有的列名称都必须被显式指定。
作为一个使用ENCRYPTION 和SCHEMABINDING选项的示例,下面的代码重新创建我前面使用过的VcustsWithOrders视图。
USE Northwind;
GO
IF OBJECT_ID(‘dbo.VcustsWithOrders’) IS NOT NULL
DROP VIEW dbo.VcustsWithOrders;
GO
CREATE VIEW dbo.VcustsWithOrders WITH ENCRYPTION, SCHEMABINDING
AS
SELECT CustomerID, CompanyName, ContactName, ContactTitle,
Address, City, Region, PostalCode, Country, Phone, Fax
FROM dbo.Customers AS C
WHERE EXISTS
(SELECT 1 FROM dbo.Orders AS O
WHERE O.CustomerID = C.CustomerID);
GO
注意 如果视图已经存在,使用ALTER
VIEW命令比删除后再重建视图要更明智,因为ALTER VIEW可以保持权限。
注意,我在子查询的SELECT列表中用常量1代替了*,这样就符合了SCHEMABINDING选项的要求。
尝试获取视图的文本:
EXEC sp_helptext ‘dbo.VcustsWithOrders’;
你会得到下面的输出:
The text for object ‘dbo.VcustsWithOrders’ is encrypted.
试着修改一个被引用列:
ALTER TABLE dbo.Customers DROP COLUMN Address;
你会收到下面的错误:
Msg 5074, Level 16, State 1, Line 1
The object ‘VcustsWithOrders’ is dependent on column ‘Address’.
Msg 4922, Level 16, State 9, Line 1
ALTER TABLE DROP COLUMN Address failed because one or more objects access this column.
CHECK OPTION
使用WITH CHECK OPTION创建的视图会防止与视图的查询筛选器有冲突的INSERT 和UPDATE语句。没有该选项,视图可以接受不符合查询筛选器的修改。例如,VcustsWithOrders视图接受下面的INSERT,即使代码会插入尚未发生订单的新消费者。
INSERT INTO dbo.VcustsWithOrders(CustomerID, CompanyName)
VALUES(N’ABCDE’, N’Company ABCDE’);
新的消费者被添加到Customers表中,但很明显,当查询该视图时,你找不到这个新的消费者,因为视图只包含发生过订单的消费者:
SELECT CustomerID, CompanyName
FROM dbo.VcustsWithOrders
WHERE CustomerID = N’ABCDE’;
该查询返回一个空集。
如果你直接查询Customers表,就可以看到这个新增的消费者了。
SELECT CustomerID, CompanyName
FROM dbo.Customers
WHERE CustomerID = N’ABCDE’;
该查询返回消费者ABCDE相关的信息。
接下来运行下面的代码为视图的定义中添加CHECK OPTION选项。
ALTER VIEW dbo.VcustsWithOrders WITH ENCRYPTION, SCHEMABINDING
AS
SELECT CustomerID, CompanyName, ContactName, ContactTitle,
Address, City, Region, PostalCode, Country, Phone, Fax
FROM dbo.Customers AS C
WHERE EXISTS
(SELECT 1 FROM dbo.Orders AS O
WHERE O.CustomerID = C.CustomerID)
WITH CHECK OPTION;
GO
注意 修改视图时,必须重新指定所有需要保留的选项,在我们的示例中包括ENCRYPTION
和SCHEMABINDING。如果你在ALTER语句中未指定这些选项,它们将不会有效。
现在尝试插入与筛选器冲突的行。
INSERT INTO dbo.VcustsWithOrders(CustomerID, CompanyName)
VALUES(N’FGHIJ’, N’Company FGHIJ’);
你会收到下面的错误:
Msg 550, Level 16, State 1, Line 1
The attempted insert or update failed because the target view either specifies WITH CHECK OPTION or spans a view that specifies WITH CHECK OPTION and one or more rows resulting from
the operation did not qualify under the CHECK OPTION constraint.
The statement has been terminated.
VIEW_METADATA
只有当客户端的请求最终会生成以视图为目标的T-SQL代码时,SQL Server才可以控制该请求通过视图来的查询或修改数据。但是,当客户端通过DB-Library、ODBC或OLEDB API请求浏览模式(browse-mode)的元数据时会出现一些问题。浏览模式元数据是SQL Server向客户端API返回的基表(base table)和结果集列的元数据。当然,如果客户端选择用基表而不是视图作为目标来构造语句,用户的请求可能不会按预期的那样执行。
假设用户拥有对一个视图的权限,但没有对其基础表(underlying table)的权限。该用户尝试对视图执行一些操作。如果客户端工具对基础表构造的语句需要请求浏览模式的元数据,该语句将会因为违背安全(security violation)而失败。另一方面,如果用户尝试通过视图修改数据,而该操作又与视图上定义的CHECK OPTION有冲突,这种操作只有直接提交到基础表,才有可能成功。
SQL Server 2000中的企业管理器(EM)就是这样的一个工具,当你通过视图以图形化形式操作数据时(右键单视图名称,然后选择打开视图并返回所有数据),它会请求浏览模式的元数据信息。如果你在操作视图数据时跟踪企业管理器提交到SQL Server中的操作,你会发现操作实际上是把基础表作为目标提交的。例如,使用企业管理器通过VcustsWithOrders尝试插入一个消费者。在CustomerID列指定FGHIJ并把公司FGHIJ作为CompanyName列的值。你会发现尽管该尝试应该因违反CHECK OPTION而失败,但实际上该操作可以被接受,该行将被添加到Customers表。如果你跟踪企业管理器对SQL Server提交的操作,就会明白它为什么会成功。跟踪中会显示下面的语句:
exec sp_executesql N’INSERT INTO “Northwind”.”dbo”.”Customers” (“CustomerID”,”CompanyName”)
VALUES (@P1,@P2)’, N’@P1 nvarchar(5),@P2 nvarchar(40)’,
N’FGHIJ’, N’Company FGHIJ’
EM构造的语句是针对Customers表而不是视图的。SQL Server Management Studio (SSMS)部分地解决了这个问题。如果在视图/查询设计器结果面板中进行操作,类似的尝试还是可以成功执行。但如果在由“打开视图”产生的面板中进行操作,将会失败。对于后者,你会在跟踪中发现下面的语句,它表明操作是提交给视图的。
exec sp_executesql N’INSERT INTO VcustsWithOrders(CustomerID, CompanyName) VALUES (@Customer ID, @CompanyName)’,N’@CustomerID
nvarchar(5),@CompanyName nvarchar(13)’,@CustomerID=N’FGHIJ’,@CompanyName=N’Company FGHIJ’
如果你希望客户端API请求浏览模式(browse mode)的元数据时SQL Server发送视图的元数据信息,而不是发送基础表的元数据信息,可以在创建或修改视图时指定VIEW_METADATA选项,就像这样。
ALTER VIEW dbo.VcustsWithOrders
WITH ENCRYPTION, SCHEMABINDING, VIEW_METADATA
AS
SELECT CustomerID, CompanyName, ContactName, ContactTitle,
Address, City, Region, PostalCode, Country, Phone, Fax
FROM dbo.Customers AS C
WHERE EXISTS
(SELECT 1 FROM dbo.Orders AS O
WHERE O.CustomerID = C.CustomerID)
WITH CHECK OPTION;
GO
完成后,执行下面的代码进行清理:
USE Northwind;
GO
DELETE FROM dbo.Customers
WHERE CustomerID IN(N’ABCDE’, N’FGHIJ’);
GO
IF OBJECT_ID(‘dbo.VcustsWithOrders’) IS NOT NULL
DROP VIEW dbo.VcustsWithOrders;
GO