2008-10-23 31 views
7

假设我使用的是Northwind数据库,并且希望通过包含其他参数的存储过程运行查询,以下:使用SQL Server 2005中的ROW_NUMBER()OVER()对不同列进行排序的分页查询

  • @Offset指示分页开始的地方,
  • @Limit指示页面大小,
  • @SortColumn指示用于排序的目的列,
  • @SortDirection,表示上升或下降的排序。

这个想法是做数据库的分页,因为结果集包含数以千计的行,所以缓存不是一个选项(并且使用VIEWSTATE甚至不被视为IMO)。

正如你可能知道SQL Server 2005提供的功能ROW_NUMBER返回结果集的分区内的行的顺序号,从1开始的每个分区的第一行。

我们需要对每个返回的列进行排序(本例中为5个),并且动态SQL不是一个选项,所以我们有两种可能性:使用大量的IF ... ELSE ...并有10个查询,这是一个地狱要维护的,查询如下所示:

WITH PaginatedOrders AS (
    SELECT 
     CASE (@SortColumn + ':' + @SortDirection) 
      WHEN 'OrderID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID ASC) 
      WHEN 'OrderID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID DESC) 
      WHEN 'CustomerID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.CustomerID ASC) 
      WHEN 'CustomerID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.CustomerID DESC) 
      WHEN 'EmployeeID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.EmployeeID ASC) 
      WHEN 'EmployeeID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.EmployeeID DESC) 
      WHEN 'OrderDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderDate ASC) 
      WHEN 'OrderDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderDate DESC) 
      WHEN 'ShippedDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID ASC) 
      WHEN 'ShippedDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID DESC) 
     END AS RowNumber, 
     OrderID, CustomerID, EmployeeID, OrderDate, ShippedDate 
    FROM Orders 
    -- WHERE clause goes here 
) 
SELECT 
    RowNumber, OrderID, CustomerID, EmployeeID, OrderDate, ShippedDate, 
    @Offset, @Limit, @SortColumn, @SortDirection 
FROM PaginatedOrders 
WHERE RowNumber BETWEEN @Offset AND (@Offset + @Limit - 1) 
ORDER BY RowNumber 

我试着查询了几次,使用不同的参数,它的表现是相当不错的实际,但它剧照看起来像它可能被优化的一些其他的方式。

这个查询有什么问题,或者你会这样做吗?你提出一个不同的方法?

+0

我的愚蠢的错误,修正了。请再试一次。 – Tomalak 2008-10-27 14:28:18

回答

6

简单:

SELECT 
    OrderID, CustomerID, EmployeeID, OrderDate, ShippedDate, 
    @Offset, @Limit, @SortColumn, @SortDirection 
FROM 
    Orders 
WHERE 
    ROW_NUMBER() OVER 
    (
    ORDER BY 
     /* same expression as in the ORDER BY of the whole query */ 
) BETWEEN (@PageNum - 1) * @PageSize + 1 AND @PageNum * @PageSize 
    /* AND more conditions ... */ 
ORDER BY 
    CASE WHEN @SortDirection = 'A' THEN 
    CASE @SortColumn 
     WHEN 'OrderID' THEN OrderID 
     WHEN 'CustomerID' THEN CustomerID 
     /* more... */ 
    END 
    END, 
    CASE WHEN @SortDirection = 'D' THEN 
    CASE @SortColumn 
     WHEN 'OrderID' THEN OrderID 
     WHEN 'CustomerID' THEN CustomerID 
     /* more... */ 
    END 
    END DESC 

如果选择ASC顺序,或者反之亦然这将排序NULL(DESC)。

让ROW_NUMBER()函数在相同的ORDER BY表达式上工作。

+0

今天下午我会试着用查询计划器和分析器的这个功能,只是为了比较结果:) – 2008-10-27 12:20:46

相关问题