章的结果,我决定在我的测试中放弃该方法
升序-降序
这个方法在子查询中使用默认排序,在主查询中使用反向排序,原理是这样的:
DECLARE @temp TABLE(
PK /* PKType */
NOT NULL PRIMARY
)
INSERT INTO @temp SELECT TOP @PageSize PK FROM
(
SELECT TOP(@StartRow + @PageSize )
PK,
SortColumn /* If sorting column is defferent from the PK,SortColumn must
be fetched as well,otherwise just the PK is necessary
*/
ORDER BY SortColumn
/*
defaultorder–typicallyASC
*/
)
ORDER BY SortColumn
/*
reversed default order–typicallyDESC
*/
SELECT... FROM Table JOIN @Temp temp ON Table .PK= temp .PK
ORDER BY SortColumn
/*
defaultorder
*/
行计数
这个方法的基本逻辑依赖于SQL中的SET ROWCOUNT表达式,这样可以跳过不必要的行并且获得需要的行记录:
DECLARE @Sort /* the type of the sorting column */
SET ROWCOUNT @StartRow
SELECT @Sort=SortColumn FROM Table ORDER BY SortColumn
SET ROWCOUNT @PageSize
SELECT... FROM Table WHERE SortColumn >= @Sort ORDER BY SortColumn
子查询
还有两个方法也是我考虑过的,他们的来源不同。第一个是众所周知的三角查询(Triple Query)或者说自查询方法,在本文中,我也用一个类似的包含所有其他存储过程的通用逻辑。这里的原理是连接到整个过程中,我对原始代码做了一些缩减,因为recordcount在我的测试中不需要)
SELECT... FROM Table WHERE PK IN(
SELECT TOP @PageSize PK FROM Table WHERE PK NOT IN
(
SELECT TOP @StartRow PK FROM Table ORDER BY SortColumn)
ORDER BY SortColumn)
ORDER BY SortColumn
游标
在看google讨论组的时候,我找到了最后一个方法。该方法是用了一个服务器端动态游标。许多人试图避免使用游标,因为游标没有关系可言,以及有序性导致其效率不高,但回过头来看,分页其实是一个有序的任务,无论你使用哪种方法,你都必须回到开始行记录。在之前的方法中,先选择所有在开始记录之前的所有行,加上需要的行记录,然后删除所有之前的行。动态游标有一个FETCH RELATIVE选项可以完成魔法般的跳转。基本的逻辑如下:
DECLARE @PK /* PKType */
DECLARE @tblPK
TABLE(
PK /*PKType*/ NOT NULL PRIMARY KEY
)
DECLARE PagingCursor CURSOR DYNAMICREAD_ONLY FOR
SELECT @PK FROM Table ORDER BY SortColumn
OPEN PagingCursor
FETCH RELATIVE @StartRow FROM PagingCursor INTO @PK
WHILE @PageSize>0 AND @@FETCH_STATUS =0
BEGIN
INSERT @tblPK(PK) VALUES(@PK)
FETCH NEXT FROM PagingCursor INTO @PK
SET @PageSize = @PageSize - 1
END
CLOSE
PagingCursor
DEALLOCATE
PagingCursor
SELECT... FROM Table JOIN @tblPK temp ON Table .PK= temp .PK
ORDER BY SortColumn
复杂查询的通用化
我在之前指出,所有的存储过程都是用动态SQL实现通用性的,因此,理论上它们可以用任何种类的复杂查询。下面有一个基于Northwind数据库的复杂查询例子。
SELECT Customers.ContactName AS Customer, Customers.Address + '' , '' + Customers.City + '', ''+ Customers.Country
AS Address, SUM([OrderDetails].UnitPrice*[ OrderDetails ] .Quantity)
AS [Totalmoneyspent]
FROM Customers
INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID
INNER JOIN [ OrderDetails ] ON Orders.OrderID = [ OrderDetails].OrderID
WHERE Customers.Country <> ''USA'' AND Customers.Country <> ''Mexico ''
GROUP BY Customers.Contac
|