SQL Server 2005でROW_NUMBER()OVER()を使用して異なる列で並べ替えを使用したページ分割クエリ

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

  •  04-07-2019
  •  | 
  •  

質問

Northwindデータベースを使用しており、他のパラメーターの中でも特に以下を含むストアドプロシージャを介してクエリを実行するとします。

  • @Offset でページ区切りの開始位置を示します
  • @Limit でページサイズを示します
  • @SortColumn は、ソートに使用される列を示します。
  • @SortDirection 、上位または下位のソートを示します。

結果セットには数千の行が含まれているため、データベースでページネーションを実行するという考え方です。したがって、キャッシングはオプションではありません(VIEWSTATEの使用はIMOであるとは見なされません)。

ご存知かもしれませんが、SQL Server 2005は ROW_NUMBER という機能を提供します。 結果セットのパーティション内の行の連続番号を返します。各パーティションの最初の行の1から始まります

返されるすべての列でソートする必要があり(この例では5つ)、動的SQLはオプションではないため、2つの可能性があります: 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)でソートされます。逆も同様です。

同じORDER BY式でROW_NUMBER()関数が機能するようにします。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top