细说Sql Server中的视图

1.什么是视图

   视图是由一个查询所定义的虚拟表,它与物理表不同的是,视图中的数据没有物理表现形式,除非你为其创建一个索引;如果查询一个没有索引的视图,Sql Server实际访问的是基础表。

   如果你要创建一个视图,为其指定一个名称和查询即可。Sql Server只保存视图的元数据,用户描述这个对象,以及它所包含的列,安全,依赖等。当你查询视图时,无论是获取数据还是更新数据,Sql server都用视图的定义来访问基础表;

   视图在我们日常操作也扮演着许多重要的角色,比如可以利用视图访问经过筛选和处理的数据,而不是直接访问基础表,以及在一定程度上也保护了基础表。

   我们在创建视图的时候,也要遵守三个规则:

    1. 不能在视图定义中指定ORDER BY ,除非定义中包含Top或For Xml 说明;
    2. 所有的列必须有列名;
    3. 这些所有的列名必须唯一;

    对于视图表中在没有top或for xml说明的情况下,不能有Order by 语句,这是因为视图被认为是一个表,表是一个逻辑的实体,它的行是没有顺序的。视图中所有列必须有列名,且唯一的情况我想大家都理解;

下面的sql语句表示创建一个简单的视图:

   1:  CREATE VIEW dbo.V1
   2:  AS
   3:  SELECT CustomerID,CompanyName FROM Customers 
   4:  WHERE EXISTS(SELECT * FROM Orders WHERE Customers.CustomerID = Orders.CustomerID)
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
2.为什么要使用视图(更新)
      SqlServer既然给我们提供这样的对象,就一定有它的作用。而我们在使用视图上,要么用的过多,要么用的不够,所以一部分人建议不要用视图,而一部分人又建议少用。那我们听谁的呢?
      其实我们要是掌握了用视图的目的,就能在正确的地方,用正确的视图;那么视图能给我们解决什么问题呢?
            1,为最终用户减少数据库呈现的复杂性。客户端只要对视图写简单的代码,就能返回我所需要的数据,一些复杂的逻辑操作,放在了视图中来完成;
            2,防止敏感的列被选中,同时仍然提供对其他重要数据的访问;
            3,对视图添加一些额外的索引,来提高查询的效率;
      视图其实没有改变任何事情,只是对访问的数据进行了某种形式的筛选。考虑一下视图的作用,你应该能看到视图的概念如何为缺乏经验的用户简化数据(只显示他们关心的数据),或者不给予用户访问基础表的
权利,但授予他们访问不包含敏感数据视图的权力,从而提前隐藏敏感数据。
      要知道,在默认的情况下,视图没有做什么特殊的事情。视图就好象一个查询那样从命令行运行(这里不存在任何形式的预先优化),这意味着在数据请求和将被交付的数据之间多加了一层开销。这表明视图绝不可能像
只是直接运行底层SELECT语句那样快。不过,视图存在有一个原因--这就是它的安全性或为用户所做的简化,在你的需要和开销之间权衡,找到最适合特定情况的解决方案。
3.视图中的ORDER BY
    视图表示一个逻辑实体,它与表非常类似;
    如果我们在上面的创建的sql语句中加一个Order BY 语句,看看有什么效果:
   1:  ALTER VIEW dbo.V1
   2:  AS 
   3:  SELECT CustomerID,CompanyName FROM Customers 
   4:  WHERE EXISTS(SELECT * FROM Orders WHERE Customers.CustomerID = Orders.CustomerID)  
   5:  ORDER BY CompanyName
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } 

运行该语句将会失败,回收到以下的提示:

Msg 1033, Level 15, State 1, Procedure V1, Line 5
除非另外还指定了 TOP 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效。

根据提示,ORDER By 也不是不能用,只有指定了Top或for xml语句后,ORDER BY 才能使用,如:
 

   1:  ALTER VIEW dbo.V1
   2:  AS 
   3:  SELECT TOP(10) CustomerID,CompanyName FROM Customers 
   4:  WHERE EXISTS(SELECT * FROM Orders WHERE Customers.CustomerID = Orders.CustomerID)  
   5:  ORDER BY CompanyName
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

      但是,并不建议在视图中使用ORDER BY ,这是因为视图表示一个表,而对于表来说,是不会有排序的;所以建议在查询视图的时候,用ORDER BY;

      SQL Server2005联机丛书有一段这样的描述:“在视图、内联函数、派生表或子查询的定义中使用ORDER BY 字句,子句只能用户确定TOP子句返回的行。ORDER BY 不保证在查询这些构造时得到有序结果,除非在查询本省也指定了ORDER BY.”

4.刷新视图

我在上面说过,视图会保存元数据,列,安全,以及依赖等信息,如果我们把基础表的架构更改了,并不会直接反映到视图上来;更改架构后,使用sp_refreshview存储过程刷新视图的元数据是一个好习惯;

比如我们创建了一个表T1和一个T1的视图V1,然后更改T1,再看V1的结果:

首先创建表T1:

   1:  IF OBJECT_ID('T1') IS NOT NULL
   2:      DROP TABLE T1
   3:   
   4:  CREATE TABLE T1(col1 INT,col2 INT)
   5:  INSERT INTO T1(col1,col2) VALUES(1,2)
   6:  GO
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }然后创建T1的视图V1:
   3:  CREATE VIEW V1
   4:  AS 
   5:  SELECT * FROM T1
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

 

       在现实实践中,要避免在视图中的SELECT语句中使用*,在这只是演示。如果你查询视图V1就会出现以下结果:
        tmp16

       接下来,我们对表T1添加一列col3:
      

   1:  ALTER TABLE T1 ADD col3 INT
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }       然后再次查询视图V1,你想这时的结果是三列呢,还是而列呢?答案是二列。T1架构的改变,并没有影响到视图的元数据中,这时候,如果我们要刷新一下视图V1,我们就可以用:EXEC sp_refreshview V1 命令, 再次查询,V1的结果就是三列了。

5.更新视图

      视图是一个虚拟表,我们在查询视图的时候,实际上是对基础表的查询。视图不仅可以作为SELECT查询的目标,也可以作为修改语句的目标。当然,当你修改视图的时候,修改的时候是对基础表的修改,它就好像是一个代理。当然,如果不允许直接修改基础表,只允许修改视图,就可以限制你要公开的数据。这样,就可以对你的数据起到一定的保护作用,不过这种限制的时候很少。

      那么在更新视图的时候,有哪些限制条件呢?

    1,只要视图有一列不能隐式获取值,你就不能想视图中插入数据,如果列允许NULL、有默认值或者IDETITY属性,则说明它可以隐式获取值;

    2,如果视图包含联结,UPDATE或INSERT语句只能影响联结的一端。也就是说,INSERT或UPDATE语句必须定义目标列列表,这些列只能数据联结的一端。你不能从由联结查询定义的视图中删除数据;

    3,不能修改作为计算结果的列。如:标量表达式和聚合函数,SqlServer不会尝试改变数据库引擎的计算结果;

    4,如果在创建或修改视图时指定了WITH CHECK OPTION选项,与视图的查询筛选器有冲突的INSERT或UPDATE语句将被拒绝;我在“视图选项”一节详细讲解一下。

   如果视图上定义了INSERT OF触发器,则违反这些限制的数据修改语句可以被执行。在INSERT OF触发器中你可以用自己的代码替换原始修改;

   当你允许对有联结查询定义的视图执行修改的时候,一定要谨慎,比如一对多的关系,如果你根据“多”的某一索引值修改对应“一”端某列值的记录,那么结果就可想而知;

 6.视图选项

   当你创建或修改视图时,可以指定一些选项,这些选项用户控制视图的行为和功能。

   ENCRYPTION、SCHEMABINDING和VIEW_METADATA选项在视图头指定,CHECK OPTION选项则在查询之后指定;

   如:        

   1:  CREATE VIEW v2
   2:  WITH ENCRYPTION,SCHEMABINDING,VIEW_METADATA
   3:  AS
   4:  SELECT OrderID FROM dbo.Orders
   5:  WITH CHECK OPTION

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

    1),ENCRYPTION

如果你在构建任何类型的商业软件的时候,需要对视图进行加密的时候,这是一个不错的选项。

如果未指定ENCRYPTION选项,SQLSERVEr则以纯文本的形式保存用户定义的语句,如果指定了ENCRYPTION选项,对象的文本则会被混淆。

SQLSERVER提供了一个系统函数sp_helptext查看视图的文本,如果应用的ENCRYPTION选项,则会得到“The text for object ‘xx’ is encrypted”语句;

注:在加密之前一定要先备份你所要加密的视图,一旦加密,就不能回头。

    2),SCHEMABINDING

如果你使用SCHEMABINDING选项创建视图,SQLSERVER将不允许删除基础表或修改被引用的列,防止在对底层对象修改时,使视图变得“孤立”,如果某人没有注意到你的视图,执行了DROP,删除视图引用的列或其他一些操作,那就很糟糕。如果使用SCHEMABINDING选项,则就可以避免这种情况。

如果想在视图上创建索引,则必须使用SCHMABINDING选项;

如果应用这个选项,则定义视图的时候要注意两点:

   1,所有对象必须由两部分构成的名称,如:应该使用dbo.Orders 而不能是Orders

   2,不能在SELECT列表使用*,所有的列名必须指定一个名称;

    3),CHECK OPTION

使用WITH CHECK OPTION 创建的视图能防止与视图查询筛选器有冲突的INSERT或UPDATE语句。没有该选项,视图可以接受不符合查询筛选器的修改。比如:

我们在Northwind数据库中创建一个CustomWithOrder的视图,现在还没有添加WITH CHECK OPTION选项

   1:  CREATE VIEW CustomerWithOrder
   2:  WITH VIEW_METADATA
   3:  AS
   4:   
   5:  SELECT Customers.CustomerID,Customers.CompanyName FROM Customers 
   6:  WHERE EXISTS(SELECT 1 FROM Orders WHERE Orders.CustomerID = Customers.CustomerID)
   7:   
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
 该视图的作用是查询所有有订单的客户的id和公司名,接下来我们向视图中插入一条不存在的用户id,和公司名:
   1:  INSERT INTO CustomerWithOrder(CustomerID,CompanyName) VALUES('MYSQL','MyReed')
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
执行成功,然后在查询这个CustomerWithOrder视图,很明显,查询不到CustomerID为’MySQL’的用户,因为视图只包含发生过订单的用户;如果你直接查询Customers表,就会发现这个新增的用户信息了。
接下来对CustomerWithOrder视图添加WITH CHECK OPTION 选项
   1:  ALTER VIEW CustomerWithOrder
   2:  WITH VIEW_METADATA
   3:  AS
   4:   
   5:  SELECT Customers.CustomerID,Customers.CompanyName FROM Customers 
   6:  WHERE EXISTS(SELECT 1 FROM Orders WHERE Orders.CustomerID = Customers.CustomerID)
   7:   
   8:  WITH CHECK OPTION
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
然后再执行下面的语句:

转载于:http://blog.itpub.net/16436858/viewspace-622139/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值