row_number over ejemplos ejemplo sql-server-2005 pagination

sql-server-2005 - over - row_number() sql server



Consulta paginada utilizando ordenaciĆ³n en columnas diferentes usando ROW_NUMBER() OVER() en SQL Server 2005 (1)

Sencillo:

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

Esto ordenará en NULL (DESC) si se selecciona el orden ASC, o viceversa.

Deje que la función ROW_NUMBER () funcione sobre la misma expresión ORDER BY.

Supongamos que estoy usando la base de datos de Northwind y me gustaría ejecutar una consulta a través de un procedimiento almacenado que contiene, entre otros parámetros, lo siguiente:

  • @Offset para indicar dónde comienza la paginación
  • @Limit para indicar el tamaño de la página,
  • @SortColumn para indicar la columna utilizada para fines de clasificación,
  • @SortDirection , para indicar la ordenación ascendente o descendiente.

La idea es hacer la paginación en la base de datos, ya que el conjunto de resultados contiene miles de filas, por lo que el almacenamiento en caché no es una opción (y usar VIEWSTATE ni siquiera se considera como, IMO, es una mierda).

Como sabrá, SQL Server 2005 proporciona la función ROW_NUMBER que devuelve el número secuencial de una fila dentro de una partición de un conjunto de resultados, comenzando en 1 para la primera fila en cada partición .

Necesitamos clasificar en cada columna devuelta (cinco en este ejemplo) y el SQL dinámico no es una opción, así que tenemos dos posibilidades: usar mucho IF ... ELSE ... y tener 10 consultas, lo cual es un infierno de mantener, o teniendo una consulta como la siguiente:

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

He intentado la consulta varias veces, con diferentes argumentos, y su rendimiento es bastante bueno en realidad, pero parece que podría ser optimizado de otra manera.

¿Pasa algo con esta consulta o lo harías de esta manera? ¿Propones un enfoque diferente?