Pregunta

Muchas aplicaciones tienen cuadrículas que muestran datos de una tabla de base de datos, una página a la vez.Muchos de ellos también permiten al usuario elegir la cantidad de registros por página, ordenar por cualquier columna y navegar hacia adelante y hacia atrás a través de los resultados.

¿Cuál es un buen algoritmo para implementar este patrón sin llevar la tabla completa al cliente y luego filtrar los datos en el cliente?¿Cómo se pueden mostrar solo los registros que se desean mostrar al usuario?

¿LINQ simplifica la solución?

¿Fue útil?

Solución

En MS SQL Server 2005 y superior, NUMERO DE FILA() parece funcionar:

T-SQL:Paginación con ROW_NUMBER()

DECLARE @PageNum AS INT;
DECLARE @PageSize AS INT;
SET @PageNum = 2;
SET @PageSize = 10;

WITH OrdersRN AS
(
    SELECT ROW_NUMBER() OVER(ORDER BY OrderDate, OrderID) AS RowNum
          ,OrderID
          ,OrderDate
          ,CustomerID
          ,EmployeeID
      FROM dbo.Orders
)

SELECT * 
  FROM OrdersRN
 WHERE RowNum BETWEEN (@PageNum - 1) * @PageSize + 1 
                  AND @PageNum * @PageSize
 ORDER BY OrderDate
         ,OrderID;

Otros consejos

Recomiendo usar LINQ o intentar copiar lo que hace.Tengo una aplicación donde uso los métodos Take y Skip de LINQ para recuperar datos paginados.El código se parece a esto:

MyDataContext db = new MyDataContext();
var results = db.Products
    .Skip((pageNumber - 1) * pageSize)
    .Take(pageSize);

La ejecución de SQL Server Profiler revela que LINQ está convirtiendo esta consulta en SQL similar a:

SELECT [ProductId], [Name], [Cost], and so on...
FROM (
    SELECT [ProductId], [Name], [Cost], [ROW_NUMBER]
    FROM (
       SELECT ROW_NUMBER() OVER (ORDER BY [Name]) AS [ROW_NUMBER], 
           [ProductId], [Name], [Cost]
       FROM [Products]
    )
    WHERE [ROW_NUMBER] BETWEEN 10 AND 20
)
ORDER BY [ROW_NUMBER]

En inglés simple:
1.Filtre sus filas y use la función ROW_NUMBER para agregar números de fila en el orden que desee.
2.Filtre (1) para devolver solo los números de fila que desea en su página.
3.Ordene (2) por el número de fila, que es el mismo que el orden que deseaba (en este caso, por Nombre).

Básicamente, existen dos formas de realizar la paginación en la base de datos (supongo que estás usando SQL Server):

Usando DESPLAZAMIENTO

Otros han explicado cómo ROW_NUMBER() OVER() La función de clasificación se puede utilizar para realizar páginas.Cabe mencionar que SQL Server 2012 finalmente incluyó soporte para el estándar SQL OFFSET .. FETCH cláusula:

SELECT first_name, last_name, score
FROM players
ORDER BY score DESC
OFFSET 40 ROWS FETCH NEXT 10 ROWS ONLY

Si está utilizando SQL Server 2012 y la compatibilidad con versiones anteriores no es un problema, probablemente debería preferir esta cláusula, ya que SQL Server la ejecutará de manera más óptima en los casos extremos.

Usando el método de búsqueda

Existe una forma completamente diferente, mucho más rápida, pero menos conocida, de realizar la paginación en SQL.Esto a menudo se denomina "método de búsqueda", como se describe en esta publicación de blog aquí.

SELECT TOP 10 first_name, last_name, score
FROM players
WHERE (score < @previousScore)
   OR (score = @previousScore AND player_id < @previousPlayerId)
ORDER BY score DESC, player_id DESC

El @previousScore y @previousPlayerId Los valores son los valores respectivos del último registro de la página anterior.Esto le permite buscar la página "siguiente".Si el ORDER BY la dirección es ASC, simplemente usa > en cambio.

Con el método anterior, no puede saltar inmediatamente a la página 4 sin haber obtenido primero los 40 registros anteriores.Pero a menudo, de todos modos, no querrás saltar tan lejos.En su lugar, obtiene una consulta mucho más rápida que podría recuperar datos en tiempo constante, dependiendo de su indexación.Además, sus páginas permanecen "estables", sin importar si los datos subyacentes cambian (p. ej.en la página 1, mientras estás en la página 4).

Esta es la mejor manera de implementar la paginación cuando se cargan más datos de forma diferida en aplicaciones web, por ejemplo.

Tenga en cuenta que el "método de búsqueda" también se denomina paginación de conjunto de teclas.

LINQ combinado con expresiones lambda y clases anónimas en .Net 3.5 enormemente simplifica este tipo de cosas.

Consultando la base de datos:

var customers = from c in db.customers
                join p in db.purchases on c.CustomerID equals p.CustomerID
                where p.purchases > 5
                select c;

Número de registros por página:

customers = customers.Skip(pageNum * pageSize).Take(pageSize);

Ordenar por cualquier columna:

customers = customers.OrderBy(c => c.LastName);

Obteniendo solo campos seleccionados del servidor:

var customers = from c in db.customers
                join p in db.purchases on c.CustomerID equals p.CustomerID
                where p.purchases > 5
                select new
                {
                    CustomerID = c.CustomerID,
                    FirstName = c.FirstName,
                    LastName = c.LastName
                };

Esto crea una clase anónima de tipo estático en la que puedes acceder a sus propiedades:

var firstCustomer = customer.First();
int id = firstCustomer.CustomerID;

Los resultados de las consultas se cargan de forma diferida de forma predeterminada, por lo que no hablará con la base de datos hasta que realmente necesite los datos.LINQ en .Net también simplifica enormemente las actualizaciones al mantener un contexto de datos de cualquier cambio que haya realizado y solo actualizar los campos que cambia.

Solución de Oracle:

select * from (
    select a.*, rownum rnum from (
        YOUR_QUERY_GOES_HERE -- including the order by
    ) a
    where rownum <= MAX_ROW
 ) where rnum >= MIN_ROW

Hay algunas soluciones que utilizo con MS SQL 2005.

Uno de ellos es ROW_NUMBER().Pero, personalmente, no me gusta ROW_NUMBER() porque no funciona para obtener grandes resultados (la base de datos en la que trabajo es realmente grande: más de 1 TB de datos ejecutando miles de consultas en segundos, ya sabes, grandes redes sociales). sitio).

Aquí está mi solución favorita.

Usaré una especie de pseudocódigo de T-SQL.

Busquemos la segunda página de usuarios ordenados por nombre, apellido, donde cada página tiene 10 registros.

@page = 2 -- input parameter
@size = 10 -- can be optional input parameter

if @page < 1 then begin
    @page = 1 -- check page number
end
@start = (@page-1) * @size + 1 -- @page starts at record no @start

-- find the beginning of page @page
SELECT TOP (@start)
    @forename = forename,
    @surname = surname
    @id = id
FROM
    users
ORDER BY
    forename,
    surname,
    id -- to keep correct order in case of have two John Smith.

-- select @size records starting from @start
SELECT TOP (@size)
    id,
    forename,
    surname
FROM
    users
WHERE
    (forename = @forename and surname = @surname and id >= @id) -- the same name and surname, but bigger id
    OR (forename = @forename and surname > @surname) -- the same name, but bigger surname, id doesn't matter
    OR (forename > @forename) -- bigger forename, the rest doesn't matter
ORDER BY
    forename,
    surname,
    id

En realidad, LINQ tiene métodos Saltar y Tomar que se pueden combinar para elegir qué registros se recuperan.

Échales un vistazo.

Para DB: Paginación en SQL Server 2005

Hay una discusión sobre esto. Aquí

La técnica obtiene la página número 100.000 de una base de datos de 150.000 líneas en 78 ms.

Utilizando el conocimiento del optimizador y SET ROWCOUNT, el primer ID de empleado en la página solicitada se almacena en una variable local como punto de partida.A continuación, ESTABLEZCA ROWCOUNT en el número máximo de registros que se solicita en @maximumRows.Esto permite paginar el conjunto de resultados de una manera mucho más eficiente.El uso de este método también aprovecha los índices preexistentes en la tabla, ya que va directamente a la tabla base y no a una tabla creada localmente.

Me temo que no puedo juzgar si es mejor que la respuesta aceptada actualmente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top