2013-03-03 176 views
29

我试图用ORDER BY子句创建视图。我有SQL服务器上成功创建2012 SP1,但SQL Server 2008 R2上,当我尝试重新创建它,我得到这个错误:使用ORDER BY子句创建视图

Msg 102, Level 15, State 1, Procedure TopUsers, Line 11
Incorrect syntax near 'OFFSET'.

创建视图的代码

CREATE View [dbo].[TopUsersTest] 
as 
select 
u.[DisplayName] , sum(a.AnswerMark) as Marks 
From Users_Questions us inner join [dbo].[Users] u 
on u.[UserID] = us.[UserID] 
inner join [dbo].[Answers] a 
on a.[AnswerID] = us.[AnswerID] 
group by [DisplayName] 
order by Marks desc 
OFFSET 0 ROWS 

=====================

这是图的屏幕截图

我想回报用户DisplayName的d UserTotalMarks并命令此结果为desc,因此最大结果的用户位于顶部。

+1

[不幸''OFFSET'仅在SQL Server 2012上受支持](http://msdn.microsoft.com/zh-cn/library/ms188385(v=sql.110).aspx) – 2013-03-03 16:18:06

+2

OFFSET是一个新的关键字在SQL 2012 – Phil 2013-03-03 16:18:07

+3

视图不能使用ORDER BY子句进行排序。您需要将ORDER BY子句放入任何引用该视图的查询中。为了在客户端应用程序中显示查询的结果,视图和表中的行是无序的。 – sqlvogel 2013-03-03 16:41:10

回答

52

我不确定你认为这个ORDER BY正在完成?即使您以合法的方式将做为ORDER BY置于视图中(例如,通过添加TOP子句),如果您只是从视图中进行选择,例如SELECT * FROM dbo.TopUsersTest;没有ORDER BY子句,SQL Server可以自由地以最有效的方式返回行,这不一定匹配您期望的顺序。这是因为ORDER BY过载,因为它试图达到两个目的:对结果进行排序并规定在TOP中包含哪些行。在这种情况下,TOP总会获胜(尽管取决于选择扫描数据的索引,您可能会发现您的订单按预期工作 - 但这只是巧合)。

为了达到您想要的效果,您需要将ORDER BY子句添加到从视图中提取数据的查询,而不是视图本身的代码。

所以,你的视图代码应该仅仅是:

CREATE VIEW [dbo].[TopUsersTest] 
AS 
    SELECT 
    u.[DisplayName], SUM(a.AnswerMark) AS Marks 
    FROM 
    dbo.Users_Questions AS uq 
    INNER JOIN [dbo].[Users] AS u 
     ON u.[UserID] = us.[UserID] 
    INNER JOIN [dbo].[Answers] AS a 
     ON a.[AnswerID] = uq.[AnswerID] 
    GROUP BY u.[DisplayName]; 

ORDER BY是没有意义的,以便甚至不应该包括在内。


为了说明,使用AdventureWorks2012,这里有一个例子:

CREATE VIEW dbo.SillyView 
AS 
    SELECT TOP 100 PERCENT 
    SalesOrderID, OrderDate, CustomerID , AccountNumber, TotalDue 
    FROM Sales.SalesOrderHeader 
    ORDER BY CustomerID; 
GO 

SELECT SalesOrderID, OrderDate, CustomerID, AccountNumber, TotalDue 
FROM dbo.SillyView; 

结果:

SalesOrderID OrderDate CustomerID AccountNumber TotalDue 
------------ ---------- ---------- -------------- ---------- 
43659   2005-07-01 29825  10-4020-000676 23153.2339 
43660   2005-07-01 29672  10-4020-000117 1457.3288 
43661   2005-07-01 29734  10-4020-000442 36865.8012 
43662   2005-07-01 29994  10-4020-000227 32474.9324 
43663   2005-07-01 29565  10-4020-000510 472.3108 

而且你可以从该TOPORDER BY已经完全执行计划见被SQL Server忽略和优化:

enter image description here

根本没有TOP运算符,也没有排序。 SQL Server已完全将其优化。

现在,如果您将视图更改为ORDER BY SalesID,那么您恰好会得到该视图的排序顺序,但只有 - 正如前面提到的那样 - 巧合。

但是,如果你改变你的外部查询执行ORDER BY你想:

SELECT SalesOrderID, OrderDate, CustomerID, AccountNumber, TotalDue 
FROM dbo.SillyView 
ORDER BY CustomerID; 

你得到的结果命令你想要的方式:

SalesOrderID OrderDate CustomerID AccountNumber TotalDue 
------------ ---------- ---------- -------------- ---------- 
43793   2005-07-22 11000  10-4030-011000 3756.989 
51522   2007-07-22 11000  10-4030-011000 2587.8769 
57418   2007-11-04 11000  10-4030-011000 2770.2682 
51493   2007-07-20 11001  10-4030-011001 2674.0227 
43767   2005-07-18 11001  10-4030-011001 3729.364 

而且计划仍然优化掉了TOP/ORDER BY在视图中,但添加了一种排序(以不小的代价,介意你),以显示按CustomerID排序的结果:

enter image description here

所以,故事的道德,不要把ORDER BY放在视图中。将ORDER BY放入引用它们的查询中。如果排序很昂贵,您可以考虑添加/更改索引来支持它。

+1

也为其他一些背景:http://dba.stackexchange.com/a/21437/1186 – 2013-03-04 22:50:48

+0

我明白为什么视图没有ORDER BY子句 - 但我经常编写Views作为存储查询的手段,我可​​以在SSMS或'sqlcmd' /'osql'中手动运行查询(例如管理报告),我希望结果按某种顺序排列(通常是一些“日期”列),但默认情况下它们的排列顺序不确定。如果我可以在视图上的扩展属性中存储默认的ORDER BY子句,那么当我在对象资源管理器中选择“脚本选择”时,SSMS会自动添加它。 – Dai 2017-05-31 08:27:13

+1

@Dai也许你应该将查询存储为存储过程而不是视图。 – 2017-05-31 15:37:43

3

的SQL Server给我们修补程序,所以我们可以订单创建视图BY

这里是链接

Micorosft HotFix SQL Server

希望这将有助于。

+0

呃,为什么这还没有被整合到SQL Server 2012呢? – 2013-12-16 06:23:23

+1

错误的事情可能是这个断开的链接。 – 2016-12-02 15:32:21

0

错误是:FROM (SELECT empno,name FROM table1 where location = 'A' ORDER BY emp_no)

和解决方案是:FROM (SELECT empno,name FROM table1 where location = 'A') ORDER BY emp_no

24

我已经成功迫使以便利用责令

SELECT TOP 9999999 ... ORDER BY something 

不幸的是使用SELECT TOP 100 PERCENT由于问题here不起作用。

+2

This Works!谢谢! – LastTribunal 2014-02-21 15:32:01

+0

谢谢!顺便说一下,'TOP'接受'bigint',所以我猜这可能会更大。所以当运行'select top 1000'时,SSMS会浪费这个订单(Aaron的回答)。然而,从查询中删除“TOP 1000”比每次输入ORDER BY条款更方便。 – 2015-05-13 09:08:51

-1

只需使用TOP 100%的选择:

 CREATE VIEW [schema].[VIEWNAME] (
     [COLUMN1], 
     [COLUMN2], 
     [COLUMN3], 
     [COLUMN4]) 
    AS 
     SELECT TOP 100 PERCENT 
     alias.[COLUMN1], 
     alias.[COLUMN2], 
     alias.[COLUMN3], 
     alias.[COLUMN4] 
     FROM 
      [schema].[TABLENAME] AS alias 
      ORDER BY alias.COLUMN1 
    GO 
+2

不喜欢没有任何评论:D哇 – 2017-06-06 11:48:23

+0

**百分之百PERCENT的那些明星**不正确的语法:P – Klevi01 2018-03-05 14:21:24

+0

我试图让源代码** TOP 100 PERCENT ** bold:D – 2018-03-08 14:16:30

0

请尝试以下逻辑。

SELECT TOP(SELECT COUNT(SNO) From MyTable) * FROM bar WITH(NOLOCK) ORDER BY SNO 
-1

为了加一个ORDER BY于查看执行以下

CREATE VIEW [dbo].[SQLSTANDARDS_PSHH] 
AS 


SELECT TOP 99999999999999 
Column1, 
Column2 
FROM 
dbo.Table 
Order by 
Column1 
-1

使用过程

创建PROC MyView的 作为 开始 SELECT TOP 99999999999999 列1, 列2 从 dbo。表 订购 列1 结束

执行过程

EXEC MyView的

0

从2012年的Sql你可以强制排序,视图和子查询与OFFSET

SELECT  C.CustomerID, 
      C.CustomerName, 
      C.CustomerAge 
FROM  dbo.Customer C 
ORDER BY CustomerAge OFFSET 0 ROWS; 

警告:这应该仅在小列表上使用,因为即使进一步连接或过滤,OFFSET也会强制评估完整视图视图缩小了它的大小!

没有好的方法来强制在视图中排序而没有副作用,并且有充分的理由。