17xie > Microsoft SQL Server 2005技术内幕 > 1.2 视图中的ORDER BY
背景:                 
[本书目录] [图书首页] [本书讨论区]  
链接地址:http://www.17xie.com/read-39313.html    注册17xie 一起来写书 实现您的出书梦想!

1.2  视图中的ORDER BY

就像我曾提到的,视图的查询不允许使用ORDER BY子句是有原因的。视图表示一个逻辑实体,不像游标那样可以对行排序,从这个意义来讲,视图与表非常相似。

试着运行下面的代码,该代码将试图在VcustsWithOrders中添加ORDER BY子句。

ALTER VIEW dbo.VcustsWithOrders

AS

SELECT Country, CustomerID, CompanyName, ContactName, ContactTitle,

  Address, City, Region, PostalCode, Phone, Fax

FROM Customers AS C

WHERE EXISTS

  (SELECT * FROM dbo.Orders AS O

   WHERE O.CustomerID = C.CustomerID)

ORDER BY Country;

GO

该尝试将会失败,并收到下面的错误信息。

Msg 1033, Level 15, State 1, Procedure VcustsWithOrders, Line 10

The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.

注意,该错误并不是说ORDER BY完全被禁止,而是说只有在两种情况下可以使用该子句即指定TOP或FOR XML。TOP和FOR XML都是T-SQL的扩展,不是标准的SQL元素。TOP和ORDER BY以及ORDER BY和FOR XML是结果集规范(result set specification)的一部分,但单独的ORDER BY并不是。因此,TOP和ORDER BY以及ORDER BY和FOR XML可以出现在视图定义中,而单独的ORDER BY却不行。

如果你需要把存储的数据返回客户端,可以在视图的外部查询中指定ORDER BY子句。

SELECT Country, CustomerID, CompanyName

FROM dbo.VcustsWithOrders

ORDER BY Country;

查询视图时允许使用ORDER BY子句是有道理的,因为客户端希望得到一个物理对象——行集。而且客户端有理由期望得到经过排序的数据。

在外部查询中使用TOP选项时,ORDER BY子句有两个用处:一个是确定要选择哪些行;另一个是确定结果集中行的顺序。但是,当在表表达式中(如在视图的查询中)使用TOP选项时,ORDER BY子句只有一个功能——确定要选择的行。这种情况下,视图还是表示一个有效的表。查询视图时,不保证行会按某个特定的顺序返回,除非在视图的外部查询中也包含ORDER BY子句。当同时指定了TOP时,ORDER BY子句允许出现在视图中(或其他的表表达式中),因为它只具有逻辑功能,不具备物理功能。理解这些细节可以帮助你开发正确的代码并避免以错误的方式使用表表达式。

例如,创建排序视图的企图本身就是错误的,因为视图表示一个表,而表是不会对行排序的。众所周知,在SQL Server 2000中追求排序视图的开发人员会利用貌似系统漏洞的一个技巧。

利用这个漏洞可以创建一个非常可笑的视图,在该视图中,指定TOP 100 PERCENT以及一个ORDER BY子句,就像这样:

ALTER VIEW dbo.VcustsWithOrders

AS

SELECT TOP (100) PERCENT

  Country, CustomerID, CompanyName, ContactName, ContactTitle,

  Address, City, Region, PostalCode, Phone, Fax

FROM Customers AS C

WHERE EXISTS

  (SELECT * FROM dbo.Orders AS O

   WHERE O.CustomerID = C.CustomerID)

ORDER BY Country;

GO

注意   上面的代码假定你正在使用SQL Server 2005。因此,它使用分号来结束ALTER VIEW语句,并在TOP选项中使用括号。如果你要在SQL Server 2000中测试这段代码,需要删除括号和分号。

视图中的ORDER BY子句意味着什么呢?它的意义不是很明确,因为TOP选项不是ANSI的标准语句。但如果你从集合的角度思考一下,就会认为ORDER BY子句没有什么意义了,因为你已经选择了所有符合筛选表达式(filter expression)的行。查询视图时,SQL Server不保证输出的顺序,除非在外部查询包含ORDER BY子句。SQL Server 2005联机丛书有一段对该行为的描述:“在视图、内联函数、派生表或子查询的定义中使用 ORDER BY 时,子句只用于确定 TOP 子句返回的行。ORDER BY 不保证在查询这些构造时得到有序结果,除非在查询本身中也指定了 ORDER BY。”

即使优化器不忽略ORDER BY子句并返回排序的数据,你也不应该依赖于这种行为。有意思的是,当我在SQL Server 2000中运行下面的代码时,可以得到经过排序的数据,如表5-1所示。

SELECT Country, CustomerID, CompanyName

FROM dbo.VcustsWithOrders;

表5-1  在SQL Server 2000中该查询使用了ORDER BY的视图的输出 (被简化)

Country

CustomerID

CompanyName

Argentina

RANCH

Rancho grande

Argentina

CACTU

Cactus Comidas para llevar

Argentina

OCEAN

Océano Atlántico Ltda.

Austria

ERNSH

Ernst Handel

续表

Country

CustomerID

CompanyName

Austria

PICCO

Piccolo und mehr

Belgium

SUPRD

Suprêmes délices

Belgium

MAISD

Maison Dewey

Brazil

TRADH

Tradição Hipermercados

Brazil

WELLI

Wellington Importadora

Brazil

QUEDE

Que Delícia

然而,当我在SQL Server 2005中运行下面的查询时,却得到表5-2所示的未排序的输出。

表5-2  SQL Server 2005中查询使用了ORDER BY的视图的输出(被简化)

Country

CustomerID

CompanyName

Germany

ALFKI

Alfreds Futterkiste

Mexico

ANATR

Ana Trujillo Emparedados y helados

Mexico

ANTON

Antonio Moreno Taquería

UK

AROUT

Around the Horn

Sweden

BERGS

Berglunds snabbköp

Germany

BLAUS

Blauer See Delikatessen

France

BLONP

Blondesddsl père et fils

Spain

BOLID

Bólido Comidas preparadas

France

BONAP

Bon app’

Canada

BOTTM

Bottom-Dollar Markets

通过分析两个版本的执行计划可以解释这种差异。图5-1显示了我在SQL Server 2000中得到的执行计划,图5-2显示了SQL Server 2005中的执行计划。

图5-1  在SQL Server 2000中使用ORDER BY查询视图的执行计划

图5-2  在SQL Server 2005中查询使用了ORDER BY的视图时生成的执行计划

你可以看到,在SQL Server 2000中的执行计划使用了一个排序运算符,按Country对数据排序。而SQL Server 2005的优化器则完全忽略了TOP (100) PERCENT 和 ORDER BY的组合。优化器知道TOP和ORDER BY在这里是没意义的。因此,它并没有对数据排序。不幸的是,已经习惯了SQL Server 2000这种行为的开发人员会认为这种变化是一个bug。即使创建这种视图的所有假设都是错误的。

注意    SQL Server 2000企业管理器中的视图设计器有一个地方可以指定视图的顺序,生成包含TOP PERCENT说明符和ORDER BY子句的视图定义。开发人员可能就是这样发现这个漏洞的。不幸的是,SQL Server 2005中的SQL Server Management Studio (SSMS) 视图设计器也有一个地方可以指定视图的顺序。尽管SQL Server 2005查询处理器对TOP 100 PERCENT ‥ ORDER BY的处理与SQL Server 2000的查询处理器不同,但这种错误用法可能会继续,因为SSMS视图设计器鼓励这么做。这样一来情况就更糟了。但愿你能意识到这种方法是非常荒唐的,今后不要这么使用。

完成后,运行下面的代码删除VcustsWithOrders视图。

IF OBJECT_ID(‘dbo.VcustsWithOrders’) IS NOT NULL

  DROP VIEW dbo.VcustsWithOrders;


字数:4487    最后更新:8个月以前 [03-18 15:02]happyskynet 修改
本页编辑者:happyskynet  
[前一页]:第1章 视图  [后一页]:1.3 刷新视图
[在本页中加入书签] [收藏本书] [推荐本书]
  17xie论坛 > 本书讨论区 > 本页评论   (共0条)
发表评论

用户名称 匿名发表
评论内容
验证码

关于我们 | 版权声明 | 免责声明 | 诚聘英才 | 联系我们 | 合作伙伴 | 友情链接 | 广告合作 | 提交意见
Copyright © 2007 17xie.com 互联网协同写书平台 京ICP备08002671号