Paginated Abfrage Sortierung mit auf verschiedene Spalten mit ROW_NUMBER () OVER () in SQL Server 2005

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

  •  04-07-2019
  •  | 
  •  

Frage

Nehmen wir an, ich bin die Northwind-Datenbank, und ich möchte eine Abfrage über eine gespeicherte Prozedur ausführen, die unter anderen Parametern enthält, die folgenden:

  • @Offset um anzuzeigen, wo die Paginierung beginnt,
  • @Limit die Seitengröße, um anzuzeigen,
  • @SortColumn die Spalte zu Sortierzwecken verwendet, um anzuzeigen,
  • @SortDirection, um aufsteigend oder Nachkommen Sortierung an.

Die Idee ist es, die Paginierung auf der Datenbank zu tun, da die Ergebnismengen Tausende von Zeilen enthalten so Caching ist keine Option (und VIEWSTATE verwendet, wird nicht einmal in Betracht gezogen wie IMO, saugt).

Wie Sie SQL Server 2005 wissen stellt die Funktion ROW_NUMBER die gibt die laufende Nummer einer Zeile innerhalb einer Partition eines Ergebnismenge, auf 1 für die erste Reihe in jeder Partition beginnend .

Wir brauchen Sortierung jede zurück Säule (fünf in diesem Beispiel) auf und dynamische SQL ist keine Option, so haben wir zwei Möglichkeiten: viel IF ... ELSE ... mit und 10 Abfragen mit, die eine Hölle zu halten, oder eine Abfrage mit wie folgt aus:

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

Ich habe versucht, die Abfrage mehrmals mit verschiedenen Argumenten, und seine Leistung ist es eigentlich ganz gut, aber es stillt sieht aus wie es eine andere Art und Weise optimiert werden könnte.

Ist etwas falsch mit dieser Abfrage oder würden Sie es auf diese Weise tun? Schlagen Sie einen anderen Ansatz?

War es hilfreich?

Lösung

Ganz einfach:

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

Dieses auf NULL sortieren wird (DESC) wenn ASC Reihenfolge ausgewählt wird, oder umgekehrt.

Lassen Sie die ROW_NUMBER () Funktion Arbeit über die gleiche ORDER BY-Ausdruck.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top