2013-03-03 173 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也會強制評估完整視圖視圖縮小了它的大小!

沒有好的方法來強制在視圖中排序而沒有副作用,並且有充分的理由。