使用ORDER BY子句创建视图

El *_*7eR 38 t-sql database sql-server view sql-server-2008-r2

我正在尝试使用ORDER BY子句创建视图.我已经在SQL Server 2012 SP1上成功创建它,但是当我尝试在SQL Server 2008 R2上重新创建它时,我收到此错误:

消息102,级别15,状态1,过程TopUsers,第11行
'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
Run Code Online (Sandbox Code Playgroud)

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

这是该图的屏幕截图

我想返回用户DisplayNameUserTotalMarks秩序这一结果说明,所以用最大的成果,用户与上顶.

Aar*_*and 72

我不确定你认为这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];
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

结果:

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
Run Code Online (Sandbox Code Playgroud)

你可以从该执行计划中看到TOP,并ORDER BY已完全忽略,而SQL Server的优化掉:

在此输入图像描述

完全没有TOP操作员,没有任何排序.SQL Server完全优化了它们.

现在,如果您更改视图ORDER BY SalesID,那么您将恰好获得视图所述的排序,但只是 - 如前所述 - 巧合.

但是,如果您更改外部查询以执行ORDER BY您想要的:

SELECT SalesOrderID, OrderDate, CustomerID, AccountNumber, TotalDue
FROM dbo.SillyView
ORDER BY CustomerID;
Run Code Online (Sandbox Code Playgroud)

您可以按照自己的方式获得结果:

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
Run Code Online (Sandbox Code Playgroud)

并且该计划仍然优化了视图中的TOP/ ORDER BY,但是添加了一种排序(以不小的代价,请注意)以呈现由CustomerID以下顺序排序的结果:

在此输入图像描述

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

  • @Dai也许您应该将查询存储为存储过程而不是视图. (3认同)
  • 我理解为什么视图没有 ORDER BY 子句 - 但我经常编写视图作为存储查询的一种方式,我可以在 SSMS 或“sqlcmd”/“osql”(例如管理报告之类的东西)中手动运行该查询,并且我想要结果按某种顺序(通常是某些“日期”列),但默认情况下它们采用某种未定义的顺序。如果我可以在视图的扩展属性中存储默认的 ORDER BY 子句,当我在对象资源管理器中选择“Script SELECT”时 SSMS 会自动添加该子句,那就太好了。 (2认同)

Blu*_*eft 30

我已经成功地迫使视图被命令使用

SELECT TOP 9999999 ... ORDER BY something
Run Code Online (Sandbox Code Playgroud)

不幸的是,SELECT TOP 100 PERCENT由于这里的问题,使用不起作用.


Tom*_*ord 8

从 Sql 2012 开始,您可以使用 OFFSET 在视图和子查询中强制排序

SELECT      C.CustomerID,
            C.CustomerName,
            C.CustomerAge
FROM        dbo.Customer C
ORDER BY    CustomerAge OFFSET 0 ROWS;
Run Code Online (Sandbox Code Playgroud)

警告:这应该只用于小列表,因为即使视图上的进一步连接或过滤器减小其大小,OFFSET 也会强制评估完整视图!

没有好的方法可以真正且有充分的理由在没有副作用的情况下强制在视图中进行排序。