可能很多人在開始學sql分頁時候都是在使用TOP NOT IN的方式??赡艿浆F在還有很多人在用這種分頁的方式進行。但是有人發現問題了么?
SELECT TOP 10 * FROM dbo.Orders WHERE OrderID NOT IN (SELECT TOP 20 OrderID FROM dbo.Orders ORDER BY RequiredDate) ORDER BY dbo.Orders.RequiredDate
SELECT TOP 10 * FROM dbo.Orders WHERE OrderID NOT IN (SELECT TOP 30 OrderID FROM dbo.Orders ORDER BY RequiredDate) ORDER BY dbo.Orders.RequiredDate
OrderID編號為 10788兩條語句有重復
這是我用NORTHWND 測試的TOP方式的分頁,大家也可以測試下,這兩條語句查詢出來的結果會有重復。測試如果orderby 的列如果有重復的話那么這樣分頁出來的數據就會有重復存在。不管是倒序還是正序都會出現。如果有人有興趣的話可以試試下面這條。
SELECT TOP 10 * FROM dbo.Orders WHERE OrderID NOT IN (SELECT TOP 160 OrderID FROM dbo.Orders ORDER BY RequiredDate DESC) ORDER BY dbo.Orders.RequiredDate DESC
SELECT TOP 10 * FROM dbo.Orders WHERE OrderID NOT IN (SELECT TOP 170 OrderID FROM dbo.Orders ORDER BY RequiredDate DESC) ORDER BY dbo.Orders.RequiredDate DESC
OrderID 編號為10880兩條語句有重復
很多人都懷疑是語句哪里寫錯了或這數據有問題。我用的是微軟官方的northwnd庫,應該不會存在數據的問題。那么我語句有問題么?
以上是初學或者習慣使用了,那么我們來實現另一種在 sqlserver2000里的實現。很多人都說都換 sqlserver2005了干嘛還拿sqlserver2000來說事。我覺得只要有人在用那么問題就會一直存在就要提出解決。
那么我們繼續看sqlserver2000的臨一種寫法,表變量來做。我想很多人也都在使用這樣的方法。
DECLARE @PAGETEMP TABLE
(
__ROW_NUM INT IDENTITY(1,1),
__TID INT
)
INSERT INTO @PAGETEMP(__TID) SELECT TOP 30 OrderID FROM dbo.Orders order by RequiredDate
SELECT [@PAGETEMP].__ROW_NUM,* FROM Orders,@PAGETEMP WHERE dbo.Orders.OrderID= [@PAGETEMP].__TID AND [@PAGETEMP] .__ROW_NUM>20 AND [@PAGETEMP].__ROW_NUM<=30
首先建立一個帶自增字段的表變量 (__ROW_NUM) ,然后把對應分頁表的主鍵插入該臨時表 (__TID),這個臨時表就把查詢表的主鍵字段根據查詢條件進行了重新的自增排序。那么下一步就是根據這個重新排序好的表變量進行與查詢表關聯。得到想返回的行數。表變量分頁和05的分頁方式很像。都是根據查詢內容得到一個帶有自增序號的臨時表,然后得到需要的行數。
繼續看另一種Sqlserver2000分頁,這樣的方法也可以解決上面的重復問題。但是給排序帶來了局限性。
SELECT TOP 10 * FROM [Orders] WHERE [Orders].[OrderID]>(
SELECT MAX([__T].[OrderID]) FROM
(SELECT TOP 20 [Orders].[OrderID] AS [OrderID] FROM [Orders] ORDER BY [Orders].[OrderID]) [__T])
ORDER BY [Orders].[OrderID]
首先找到前20條數據找到最大的那一條編號。排除這20條記錄找到大于這寫記錄的前十條記錄。很容易看明白。這個必須是查詢表有自增編號。而且按這個編號排序進行分頁,有了很大的局限性。那如果倒序的話就是min和小于來過濾數據。
SELECT TOP 10 * FROM [Orders] WHERE [Orders].[OrderID]<(
SELECT MIN([__T].[OrderID]) FROM
(SELECT TOP 20 [Orders].[OrderID] AS [OrderID] FROM [Orders] ORDER BY [Orders].[OrderID] DESC) [__T])
ORDER BY [Orders].[OrderID] DESC
最后我們來看一下sqlserver2005的分頁語句,用到 ROW_NUMBER OVER 兩個關鍵字
WITH [__T] AS (
SELECT TOP 30 *,ROW_NUMBER() OVER (ORDER BY [Orders].OrderID) AS [__Pos] FROM [Orders]
)
SELECT * FROM [__T] WHERE [__T].[__Pos]>20 AND [__T].[__Pos]<=30
OVER 這里設置排序列。ROW_NUMBER() OVER (ORDER BY [Orders].OrderID) AS [__Pos]為我們建立了自增列,查詢的時候只需要返回我們需要的行號就行。這個和表變量的形式很相像。性能方面也提高了很多。
以上就是我對分頁作出的總結,主要是想說下sqlserver2000的TOP NOT IN 這種分頁方式,所以以后大家要用Sqlserver2000的話請使用后面2種方式。在新的NSun中默認是sqlserver2005的分頁,如果你是sqlserver2000則變為了表變量的方式。
新聞熱點
疑難解答