sql >> Base de Datos >  >> RDS >> Sqlserver

Paginación en SQL Server usando OFFSET/FETCH

La paginación se usa a menudo en aplicaciones en las que el usuario puede hacer clic en Anterior /Siguiente para navegar por las páginas que componen los resultados, o haga clic en un número de página para ir directamente a una página específica.

Al ejecutar consultas en SQL Server, puede paginar los resultados utilizando el OFFSET y FETCH argumentos del ORDER BY cláusula. Estos argumentos se introdujeron en SQL Server 2012, por lo tanto, puede usar esta técnica si tiene SQL Server 2012 o superior.

En este contexto, la paginación es donde divide los resultados de la consulta en partes más pequeñas, cada parte continúa donde terminó la anterior. Por ejemplo, si una consulta devuelve 1000 filas, puede paginarlas para que se devuelvan en grupos de 100. Una aplicación puede pasar el número de página y el tamaño de página a SQL Server, y SQL Server puede usarlo para devolver solo el datos de la página solicitada.

Ejemplo 1:sin paginación

Primero, ejecutemos una consulta que devuelva todas las filas de una tabla:

SELECT *
FROM Genres
ORDER BY GenreId;

Resultado:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
| 4         | Pop     |
| 5         | Blues   |
| 6         | Hip Hop |
| 7         | Rap     |
| 8         | Punk    |
+-----------+---------+

Este ejemplo no utiliza paginación:se muestran todos los resultados.

Este conjunto de resultados es tan pequeño que normalmente no requeriría paginación, pero para los propósitos de este artículo, vamos a paginarlo.

Ejemplo 2:mostrar los primeros 3 resultados

Este ejemplo muestra los tres primeros resultados:

SELECT *
FROM Genres
ORDER BY GenreId
  OFFSET 0 ROWS
  FETCH NEXT 3 ROWS ONLY;

Resultado:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+

En este caso, especifico que los resultados deben comenzar en el primer resultado y mostrar las siguientes tres filas. Esto se hace usando lo siguiente:

  • OFFSET 0 ROWS especifica que no debe haber ningún desplazamiento (un desplazamiento de cero).
  • FETCH NEXT 3 ROWS ONLY obtiene las siguientes tres filas del desplazamiento. Dado que especifiqué un desplazamiento de cero, se obtienen las tres primeras filas.

Si todo lo que queríamos eran los 3 mejores resultados, podríamos haber logrado el mismo resultado usando el TOP cláusula en lugar de especificar los valores de compensación y recuperación. Sin embargo, esto no nos hubiera permitido hacer la siguiente parte.

Ejemplo 3:mostrar los siguientes 3 resultados

Ahora vamos a mostrar los siguientes tres resultados:

SELECT *
FROM Genres
ORDER BY GenreId
  OFFSET 3 ROWS
  FETCH NEXT 3 ROWS ONLY;

Resultado:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 4         | Pop     |
| 5         | Blues   |
| 6         | Hip Hop |
+-----------+---------+

Así que lo único que cambié fue el desplazamiento.

Los valores de desplazamiento y recuperación también pueden ser una expresión proporcionada como una variable, parámetro o subconsulta escalar constante. Cuando se usa una subconsulta, no puede hacer referencia a ninguna columna definida en el alcance de la consulta externa (no se puede correlacionar con la consulta externa).

Los siguientes ejemplos usan expresiones para mostrar dos enfoques para paginar los resultados.

Ejemplo 4:paginación por número de fila

Este ejemplo usa expresiones para especificar la fila número para empezar.

DECLARE 
  @StartRow int = 1,
  @RowsPerPage int = 3;
  
SELECT *  
FROM Genres
ORDER BY GenreId ASC
    OFFSET @StartRow - 1 ROWS
    FETCH NEXT @RowsPerPage ROWS ONLY;

Resultado:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+

Aquí, uso @StartRow int = 1 para especificar que los resultados deben comenzar en la primera fila.

Esto es lo que sucede si incremento ese valor a 2 .

DECLARE 
  @StartRow int = 2,
  @RowsPerPage int = 3;
  
SELECT *  
FROM Genres
ORDER BY GenreId ASC
    OFFSET @StartRow - 1 ROWS
    FETCH NEXT @RowsPerPage ROWS ONLY;

Resultado:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 2         | Jazz    |
| 3         | Country |
| 4         | Pop     |
+-----------+---------+

Comienza en la segunda fila. Usando este método, puedo especificar la fila exacta para comenzar.

Ejemplo 5:paginación por número de página

Este ejemplo es casi idéntico al ejemplo anterior, excepto que le permite especificar el número de página, en lugar del número de fila.

DECLARE 
  @PageNumber int = 1,
  @RowsPerPage int = 3;
  
SELECT *  
FROM Genres
ORDER BY GenreId ASC
    OFFSET (@PageNumber - 1) * @RowsPerPage ROWS
    FETCH NEXT @RowsPerPage ROWS ONLY;

Resultado:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+

Así que el primer resultado es el mismo. Sin embargo, veamos qué sucede cuando incrementamos @PageNumber a 2 (Cambié el nombre de esta variable para reflejar su nuevo propósito).

DECLARE 
  @PageNumber int = 2,
  @RowsPerPage int = 3;
  
SELECT *  
FROM Genres
ORDER BY GenreId ASC
    OFFSET (@PageNumber - 1) * @RowsPerPage ROWS
    FETCH NEXT @RowsPerPage ROWS ONLY;

Resultado:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 4         | Pop     |
| 5         | Blues   |
| 6         | Hip Hop |
+-----------+---------+

Esta vez los resultados comienzan en la cuarta fila. Entonces, al usar este método, simplemente puede pasar el número de página en lugar del número de fila.

Ejemplo 6:bucle de paginación

Para terminar, aquí hay un ejemplo rápido que recorre todas las páginas y especifica el número de fila inicial para cada iteración:

DECLARE 
  @StartRow int = 1, 
  @RowsPerPage int = 3;
WHILE (SELECT COUNT(*) FROM Genres) >= @StartRow  
BEGIN
    SELECT *  
    FROM Genres 
    ORDER BY GenreId ASC   
        OFFSET @StartRow - 1 ROWS   
        FETCH NEXT @RowsPerPage ROWS ONLY;
SET @StartRow = @StartRow + @RowsPerPage;  
CONTINUE
END;

Resultado:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+
(3 rows affected)
+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 4         | Pop     |
| 5         | Blues   |
| 6         | Hip Hop |
+-----------+---------+
(3 rows affected)
+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 7         | Rap     |
| 8         | Punk    |
+-----------+---------+
(2 rows affected)

Ejemplo 7:FILA vs FILAS

Si encuentra un código que usa ROW en lugar de ROWS , ambos argumentos hacen lo mismo. Son sinónimos y se proporcionan para la compatibilidad con ANSI.

Aquí está el primer ejemplo en esta página, pero con ROW en lugar de ROWS .

SELECT *
FROM Genres
ORDER BY GenreId
  OFFSET 0 ROW
  FETCH NEXT 3 ROW ONLY;

Resultado:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+

Ejemplo 8:PRIMERO vs SIGUIENTE

Lo mismo se aplica a FIRST y NEXT . Estos son sinónimos proporcionados para la compatibilidad con ANSI.

Aquí está el ejemplo anterior pero con FIRST en lugar de NEXT .

SELECT *
FROM Genres
ORDER BY GenreId
  OFFSET 0 ROW
  FETCH FIRST 3 ROW ONLY;

Resultado:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+