SQL Server 2005에서 row_number () Over ()를 사용하여 다른 열에서 정렬을 사용한 Paginated Query

StackOverflow https://stackoverflow.com/questions/230058

  •  04-07-2019
  •  | 
  •  

문제

Northwind 데이터베이스를 사용하고 있다고 가정 해 봅시다. 다른 매개 변수 중에는 다음과 같은 저장된 절차를 통해 쿼리를 실행하고 싶다고 가정 해 봅시다.

  • @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

나는 다른 인수와 함께 여러 번 쿼리를 시도했으며, 그 성능은 실제로 상당히 좋지만 여전히 다른 방법으로 최적화 된 것처럼 보입니다.

이 쿼리에 문제가 있습니까? 아니면 이런 식으로 할 것입니까? 다른 접근법을 제안합니까?

도움이 되었습니까?

해결책

단순한:

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 () 함수가 표현식으로 동일한 순서로 작동하도록합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top