Wie schreibe ich LINQs .Skip (1000) .Take (100) in reinem SQL?

93

Was ist das SQL-Äquivalent der .Skip()Methode in LINQ?

Zum Beispiel: Ich möchte die Zeilen 1000-1100 aus einer bestimmten Datenbanktabelle auswählen.

Ist das nur mit SQL möglich? Oder muss ich die gesamte Tabelle auswählen und dann die Zeilen im Speicher finden? Ich möchte dies im Idealfall nach Möglichkeit vermeiden, da der Tisch sehr groß sein kann.

Strahl
quelle

Antworten:

78

In SQL Server 2005 und höher können Sie die Funktion ROW_NUMBER verwenden. z.B.

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
quelle
Siehe den Link in meiner Antwort für ein bisschen mehr Details. stackoverflow.com/questions/1744802/…
Mike Atlas
ZWISCHEN 51 und 60 - es ist inklusive.
Drew Miller
1
Aber dies wird zuerst alle auswählen und dann aus dieser Auswahl nur 10 nehmen, oder? Oder hat die erste Abfrage / Ansicht bereits nur 10?
Tadej
138

SQL Server 2012 und höher haben diese Syntax hinzugefügt:

SELECT *
FROM Sales.SalesOrderHeader 
ORDER BY OrderDate
OFFSET (@Skip) ROWS FETCH NEXT (@Take) ROWS ONLY
John Gietzen
quelle
11
Beachten Sie, dass Sie ORDER BY ___ verwenden müssen, um den OFFSET-Befehl zu verwenden. Nicht, dass Sie jemals versuchen sollten, ohne Befehl zu paginieren.
James Haug
Beachten Sie auch, dass die 'neue' Syntax seltsamerweise eine Leistungsbeeinträchtigung aufweist, die mit der von @skip linear ist! Der row_number-Ansatz hat dies NICHT (nur in indizierter Reihenfolge getestet). Für lo @Skip weniger als 20 ist die neue Syntax jedoch schneller als der row_number-Ansatz.
Eske Rahn
22

LINQ to SQL verwendet dazu eine ROW_NUMBER-Fensterfunktion:

  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;

Dies funktioniert, aber die Notwendigkeit, die Zeilennummer aus ORDER BY herzustellen, kann bestehen führen, dass Ihre Abfrage auf der Serverseite sortiert wird und Leistungsprobleme verursacht. Selbst wenn ein Index die ORDER BY-Anforderung erfüllen kann, muss die Abfrage vor dem Start noch 1000 Zeilen zählen, um Ergebnisse zurückzugeben. Nur allzu oft vergessen Entwickler dies und werfen einfach eine Paginierungssteuerung über eine 5-mil-Zeilentabelle und fragen sich, warum die erste Seite so viel schneller als die letzte zurückgegeben wird ...

Trotzdem ist die Verwendung von ROW_NUMBER () wahrscheinlich die beste Balance zwischen Benutzerfreundlichkeit und guter Leistung, vorausgesetzt, Sie vermeiden die Sortierung (die ORDER BY-Bedingung kann durch einen Index erfüllt werden).

Remus Rusanu
quelle
1
Vielen Dank für die zusätzlichen Leistungsinformationen, müssen vorsichtig sein und es testen.
Ray
Getestet und für meine halbe Million Zeilentabelle ist diese letzte Seite ungefähr siebenmal langsamer als die erste Seite. Nicht ideal, aber für mich akzeptabel.
Ray
6

Probier diese:

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

Beispiel:

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

Mach das:

Führen Sie .Skip (1000) .Take (100) für einen LINQ to SQL-Datenkontext aus und sehen Sie sich die SQL-Ausgabe an. Es wird eine SQL-Anweisung für Sie generiert, die das tut, was Sie beschreiben.

Es wird nicht so elegant sein, aber es erledigt den Job.

Joseph
quelle
2
Nicht was gefragt wurde.
RayLoveless