Come scrivo .Skip (1000) .Take (100) di LINQ in SQL puro?


93

Qual è l'equivalente SQL del .Skip()metodo in LINQ?

Ad esempio: vorrei selezionare le righe 1000-1100 da una tabella di database specifica.

È possibile solo con SQL? O devo selezionare l'intera tabella, quindi trovare le righe in memoria? Preferirei evitare questo, se possibile, poiché il tavolo può essere abbastanza grande.

Risposte:


78

In SQL Server 2005 e versioni successive è possibile utilizzare la funzione ROW_NUMBER . per esempio.

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

Vedi il link nella mia risposta per un po 'più in dettaglio. stackoverflow.com/questions/1744802/…
Mike Atlas

TRA 51 e 60 - è compreso.
Drew Miller

1
Ma questo selezionerà prima tutto e poi da quella selezione ne prenderà solo 10, giusto? O la prima query / visualizzazione ne avrà già solo 10?
Tadej

138

SQL Server 2012 e versioni successive hanno aggiunto questa sintassi:

SELECT *
FROM Sales.SalesOrderHeader 
ORDER BY OrderDate
OFFSET (@Skip) ROWS FETCH NEXT (@Take) ROWS ONLY

11
Nota che devi usare ORDER BY ___ per usare il comando OFFSET .... non che dovresti mai provare a impaginare senza un ordine.
James Haug

Si noti inoltre che la sintassi "nuova" ha stranamente una penalizzazione delle prestazioni lineare con @skip! L'approccio row_number NON ha questo (testato solo in ordine indicizzato). Per lo @Skip meno di circa 20, la nuova sintassi è però più veloce dell'approccio row_number.
Eske Rahn

22

LINQ to SQL esegue questa operazione utilizzando una funzione di finestra 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;

Funziona, ma la necessità di produrre il row_number da ORDER BY può comportare l'ordinamento della query sul lato server e causare problemi di prestazioni. Anche quando un indice può soddisfare il requisito ORDER BY, la query deve comunque contare 1000 righe prima di iniziare a restituire i risultati. Troppo spesso gli sviluppatori lo dimenticano e si limitano a lanciare un controllo di impaginazione su una tabella di 5 milioni di righe e si chiedono perché la prima pagina viene restituita molto più velocemente dell'ultima ...

Nondimeno, l'uso di ROW_NUMBER () è probabilmente il miglior equilibrio tra facilità d'uso e buone prestazioni, a condizione che ti assicuri di evitare l'ordinamento (la condizione ORDER BY può essere soddisfatta da un indice).


1
Grazie per le informazioni aggiuntive sulle prestazioni, dovrò stare attento e testarlo.
Ray

Testato e per la mia tabella da mezzo milione di righe, l'ultima pagina è circa 7 volte più lenta della prima pagina. Non ideale, ma accettabile per me.
Ray

6

Prova questo:

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

Esempio:

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

4

Fai questo:

Eseguire .Skip (1000) .Take (100) su un contesto di dati LINQ to SQL e osservare l'output SQL. Genererà un'istruzione SQL per te che fa ciò che stai descrivendo.

Non sarà così elegante ma porta a termine il lavoro.


2
Non quello che veniva chiesto.
RayLoveless

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.