¿Cómo escribo .Skip (1000) .Take (100) de LINQ en SQL puro?

93

¿Cuál es el equivalente SQL del .Skip()método en LINQ?

Por ejemplo: me gustaría seleccionar las filas 1000-1100 de una tabla de base de datos específica.

¿Es esto posible solo con SQL? ¿O necesito seleccionar toda la tabla y luego buscar las filas en la memoria? Lo ideal sería evitar esto, si es posible, ya que la mesa puede ser bastante grande.

Rayo
fuente

Respuestas:

78

En SQL Server 2005 y superior puede utilizar la función ROW_NUMBER . p.ej.

USE AdventureWorks;
GO
WITH OrderedOrders AS
(
    SELECT SalesOrderID, OrderDate,
    ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
    FROM Sales.SalesOrderHeader 
) 
SELECT * 
FROM OrderedOrders 
WHERE RowNumber BETWEEN 51 AND 60; --BETWEEN is inclusive
Dan Diplo
fuente
Vea el enlace en mi respuesta para obtener más detalles. stackoverflow.com/questions/1744802/…
Mike Atlas
ENTRE 51 y 60 - es inclusivo.
Drew Miller
1
Pero esto primero seleccionará todo y luego de esa selección tomará solo 10, ¿verdad? ¿O la primera consulta / vista ya tendrá solo 10?
Tadej
139

SQL Server 2012 y versiones posteriores han agregado esta sintaxis:

SELECT *
FROM Sales.SalesOrderHeader 
ORDER BY OrderDate
OFFSET (@Skip) ROWS FETCH NEXT (@Take) ROWS ONLY
John Gietzen
fuente
11
Tenga en cuenta que debe usar ORDER BY ___ para usar el comando OFFSET ... no es que deba intentar paginar sin una orden.
James Haug
También tenga en cuenta que la 'nueva' sintaxis extrañamente tiene una penalización de rendimiento lineal con @skip! El enfoque de número de fila NO tiene esto (solo probado en orden indexado). Sin embargo, para lo @Skip menos de 20, la nueva sintaxis es más rápida que el enfoque de número de fila.
Eske Rahn
22

LINQ to SQL hace esto usando una función de ventana ROW_NUMBER:

  SELECT a,b,c FROM 
   (SELECT a,b,c, ROW_NUMBER() OVER (ORDER BY ...) as row_number
    FROM Table) t0
   WHERE to.row_number BETWEEN 1000 and 1100;

Esto funciona, pero la necesidad de fabricar el número de fila a partir de ORDER BY puede hacer que su consulta se ordene en el lado del servidor y cause problemas de rendimiento. Incluso cuando un índice puede satisfacer el requisito ORDER BY, la consulta aún debe contar 1000 filas antes de comenzar a devolver resultados. Con demasiada frecuencia, los desarrolladores olvidan esto y simplemente lanzan un control de paginación sobre una tabla de filas de 5 mil y se preguntan por qué la primera página se devuelve mucho más rápido que la última ...

No obstante, usar ROW_NUMBER () es probablemente el mejor equilibrio entre facilidad de uso y buen rendimiento, siempre que se asegure de evitar la ordenación (la condición ORDER BY puede satisfacerse mediante un índice).

Remus Rusanu
fuente
1
Gracias por la información extra de rendimiento, tendrás que tener cuidado y probarlo.
Ray
Probado y para mi tabla de medio millón de filas, esa última página es aproximadamente 7 veces más lenta que la primera página. No es ideal, pero aceptable para mí.
Ray
6

Prueba este:

select * from [Table-Name] order by [Column-Name] 
offset [Skip-Count] rows
FETCH NEXT [Take-Count] rows only

Ejemplo:

select * from Personals order by Id
offset 10 rows            --------->Skip 10
FETCH NEXT 15 rows only   --------->Take 15
Fereydoon Barikzehy
fuente
4

Hacer esto:

Ejecute .Skip (1000) .Tome (100) en un contexto de datos LINQ to SQL y observe la salida SQL. Generará una declaración SQL para usted que hace lo que está describiendo.

No será tan elegante, pero hace el trabajo.

Joseph
fuente
2
No lo que se preguntaba.
RayLoveless