Wie implementiere ich LIMIT mit Microsoft SQL Server?

Antworten:

127

Wenn Sie SQL SERVER 2005 starten, können Sie dies tun ...

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 10 AND 20;

oder so ähnlich für Versionen ab 2000 ...

SELECT TOP 10 * FROM (SELECT TOP 20 FROM Table ORDER BY Id) ORDER BY Id DESC
Leon Tayson
quelle
6
Die 2. Abfrage schlägt fehl, wenn Sie zB 14 Zeilen in der Tabelle haben. Sie erhalten die Zeilen 5 bis 14, möchten jedoch die Zeilen 11 bis 14. Im Allgemeinen schlägt dies für die letzte "Seite" eines Ergebnisses fehl, es sei denn, die Gesamtzahl der Zeilen ist ein Vielfaches dieser "Seitengröße".
Bill Karwin
147
So eine einfache Sache muss MS noch einmal so schwer machen!
Martin
In SQL Server Management Studio 2017 hat Folgendes für mich funktioniert: SELECT * FROM [dbo]. <TableName hier einfügen> WHERE @@ ROWCOUNT ZWISCHEN <min hier einfügen> und <max hier einfügen>
Artorias2718
Nur fantastisch, es funktioniert wie Charme in MS SQL Server 2017 select Statement
PatsonLeaner
58

Klobig, aber es wird funktionieren.

SELECT TOP 10 * FROM table WHERE id NOT IN (SELECT TOP 10 id FROM table ORDER BY id) FROM table ORDER BY id

Das Auslassen einer LIMIT-Klausel durch MSSQL ist kriminell, IMO. Sie sollten diese Art von klobiger Problemumgehung nicht durchführen müssen.

ceejayoz
quelle
Haben Sie einen weiteren Vorschlag, um dies zu umgehen?
Bigballs
Ich habe viel gegoogelt, als ich das letzte Mal mit MSSQL zu tun hatte, und dies war die beste Lösung, die ich gefunden habe. Nicht angenehm, aber es funktioniert.
Ceejayoz
Diese Lösung funktioniert nur, wenn die Ergebnismenge eine eindeutige Spalte enthält. Es ist keine allgemeine Lösung, um LIMIT für eine Abfrage nachzuahmen.
Bill Karwin
1
Ich bin gerade in einem ähnlichen Dilemma ... In meinem Fall bin ich jedoch abgespritzt ... Es ist noch krimineller, wenn sogenannte "Experten" -DBAs entscheiden, dass ein eindeutiger Schlüssel in einer Tabelle unnötig ist ... JEDER Tisch ... Sprechen Sie nicht einmal das Thema Fremdschlüssel und Einschränkungen an!
Andrew Rollings
Das Problem mit diesem ist, dass es nicht sehr gut mit WHERE-Klauseln umgeht ... Ich werde temporäre Tabellen ausprobieren, da es für mich nicht funktioniert.
böse Pastete
37

Ab SQL Server 2012 können Sie die OFFSET FETCH-Klausel verwenden:

USE AdventureWorks;
GO
SELECT SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader 
ORDER BY SalesOrderID
    OFFSET 10 ROWS
    FETCH NEXT 10 ROWS ONLY;
GO

http://msdn.microsoft.com/en-us/library/ms188385(v=sql.110).aspx

Dies funktioniert möglicherweise nicht richtig, wenn die Bestellung von nicht eindeutig ist.

Wenn die Abfrage in ORDER BY OrderDate geändert wird, entspricht die zurückgegebene Ergebnismenge nicht den Erwartungen.

user4047259
quelle
Die Verwendung von 'mit' benötigt nur die Hälfte der Zeit, um die Abfrage abzuschließen - siehe die Antwort von @Leon Tayson. Ich habe keine Ahnung, was Microsoft getan hat, um es so langsam zu machen.
isHuman
1
Warum ist dies nicht die akzeptierte Antwort? Wir sind im Jahr 2018 für lautes Schreien!
Skipper
1
@ Skipper richtig. der akzeptierte funktioniert noch. Lassen Sie uns diesen nur verbessern, um das Update widerzuspiegeln.
Krone
18

Dies ist fast ein Duplikat einer Frage, die ich im Oktober gestellt habe: Emulieren Sie die MySQL LIMIT-Klausel in Microsoft SQL Server 2000

Wenn Sie Microsoft SQL Server 2000 verwenden, gibt es keine gute Lösung. Die meisten Benutzer müssen das Ergebnis der Abfrage in einer temporären Tabelle mit einem IDENTITYPrimärschlüssel erfassen . Fragen Sie dann anhand einer BETWEENBedingung nach der Primärschlüsselspalte .

Wenn Sie Microsoft SQL Server 2005 oder höher verwenden, verfügen Sie über eine ROW_NUMBER()Funktion, sodass Sie das gleiche Ergebnis erzielen, jedoch die temporäre Tabelle vermeiden können.

SELECT t1.*
FROM (
    SELECT ROW_NUMBER OVER(ORDER BY id) AS row, t1.*
    FROM ( ...original SQL query... ) t1
) t2
WHERE t2.row BETWEEN @offset+1 AND @offset+@count;

Sie können dies auch als allgemeinen Tabellenausdruck schreiben, wie in der Antwort von @Leon Tayson gezeigt .

Bill Karwin
quelle
ROW_NUMBER () OVER (ORDER BY) erhält Punkte für die Gültigkeit in ANSI SQL: 2003, obwohl die Unterstützung in anderen DBMS als SQL Server sehr unvollständig ist. Und es ist natürlich ziemlich klobig ...
Bobince
@bobince: Es stellt sich heraus, dass Oracle, Microsoft SQL Server 2005, IBM DB2 und PostgreSQL 8.4 alle Fensterfunktionen unterstützen. Das deckt einen großen Teil des SQL-Marktes ab. Die Unterstützung ist nur sporadisch, wenn Sie MySQL, SQLite oder eine alte Version der oben genannten DBs verwenden.
Bill Karwin
16

So beschränke ich die Ergebnisse in MS SQL Server 2012:

SELECT * 
FROM table1
ORDER BY columnName
  OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

HINWEIS: OFFSETKann nur mit oder zusammen mit verwendet werden ORDER BY.

Um die Codezeile zu erklären OFFSET xx ROWS FETCH NEXT yy ROW ONLY

Dies xxist die Datensatz- / Zeilennummer, aus der Sie in der Tabelle abrufen möchten, dh: Wenn in Tabelle 1 40 Datensätze enthalten sind, beginnt der obige Code mit dem Abrufen aus Zeile 10.

Dies yyist die Anzahl der Datensätze / Zeilen, die Sie aus der Tabelle abrufen möchten.

So bauen Sie auf dem vorherigen Beispiel auf: Wenn Tabelle 1 40 Datensätze enthält und Sie begonnen haben, aus Zeile 10 zu ziehen und den nächsten 10er-Satz zu greifen (yy ) zu . Das würde bedeuten, dass der obige Code die Datensätze aus Tabelle 1 ab Zeile 10 abruft und bei 20 endet. Auf diese Weise werden die Zeilen 10 bis 20 abgerufen.

Weitere Informationen zu OFFSET finden Sie unter dem Link

Jeremy
quelle
12
SELECT  *
FROM    (
        SELECT  TOP 20
                t.*, ROW_NUMBER() OVER (ORDER BY field1) AS rn
        FROM    table1 t
        ORDER BY
                field1
        ) t
WHERE   rn > 10
Quassnoi
quelle
Nun, ich habe gerade überprüft, dass SQL Server intelligent genug ist, um unter ROW_NUMBER () -Bedingungen anzuhalten, wenn die ORDER BY-Klausel eine indizierte Spalte enthält.
Quassnoi
9

Syntaktisch ist die MySQL LIMIT-Abfrage ungefähr so:

SELECT * FROM table LIMIT OFFSET, ROW_COUNT

Dies kann wie in Microsoft SQL Server übersetzt werden

SELECT * FROM 
(
    SELECT TOP #{OFFSET+ROW_COUNT} *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum 
    FROM table
) a
WHERE rnum > OFFSET

Jetzt wird Ihre Anfrage select * from table1 LIMIT 10,20so aussehen:

SELECT * FROM 
(
    SELECT TOP 30 *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum 
    FROM table1
) a
WHERE rnum > 10 

quelle
2

Dies ist einer der Gründe, warum ich versuche, die Verwendung von MS Server zu vermeiden ... aber trotzdem. Manchmal hast du einfach keine Option (yei! Und ich muss eine veraltete Version verwenden !!).

Mein Vorschlag ist, eine virtuelle Tabelle zu erstellen:

Von:

SELECT * FROM table

Zu:

CREATE VIEW v_table AS    
    SELECT ROW_NUMBER() OVER (ORDER BY table_key) AS row,* FROM table

Dann fragen Sie einfach:

SELECT * FROM v_table WHERE row BETWEEN 10 AND 20

Wenn Felder hinzugefügt oder entfernt werden, wird "Zeile" automatisch aktualisiert.

Das Hauptproblem bei dieser Option ist, dass ORDER BY behoben ist. Wenn Sie also eine andere Reihenfolge wünschen, müssen Sie eine andere Ansicht erstellen.

AKTUALISIEREN

Bei diesem Ansatz gibt es ein weiteres Problem: Wenn Sie versuchen, Ihre Daten zu filtern, funktioniert dies nicht wie erwartet. Wenn Sie zum Beispiel Folgendes tun:

SELECT * FROM v_table WHERE field = 'test' AND row BETWEEN 10 AND 20

WHERE wird auf die Daten beschränkt, die sich in den Zeilen zwischen 10 und 20 befinden (anstatt den gesamten Datensatz zu durchsuchen und die Ausgabe zu begrenzen).

Lepe
quelle
1

Dies ist ein mehrstufiger Ansatz, der in SQL2000 funktioniert.

-- Create a temp table to hold the data
CREATE TABLE #foo(rowID int identity(1, 1), myOtherColumns)

INSERT INTO #foo (myColumns) SELECT myData order By MyCriteria

Select * FROM #foo where rowID > 10
souLTower
quelle
1
SELECT 
    * 
FROM 
    (
        SELECT 
            top 20              -- ($a) number of records to show
            * 
        FROM
            (
                SELECT 
                    top 29      -- ($b) last record position
                    * 
                FROM 
                    table       -- replace this for table name (i.e. "Customer")
                ORDER BY 
                    2 ASC
            ) AS tbl1 
        ORDER BY 
            2 DESC
    ) AS tbl2 
ORDER BY 
    2 ASC;

-- Examples:

-- Show 5 records from position 5:
-- $a = 5;
-- $b = (5 + 5) - 1
-- $b = 9;

-- Show 10 records from position 4:
-- $a = 10;
-- $b = (10 + 4) - 1
-- $b = 13;

-- To calculate $b:
-- $b = ($a + position) - 1

-- For the present exercise we need to:
-- Show 20 records from position 10:
-- $a = 20;
-- $b = (20 + 10) - 1
-- $b = 29;
Julian Moreno
quelle
War eine großartige Lösung für mich.
Tyde
1

Müssen versuchen. In der folgenden Abfrage sehen Sie Gruppieren nach, Sortieren nach, Zeilen überspringen und Zeilen begrenzen.

select emp_no , sum(salary_amount) from emp_salary
Group by emp_no 
ORDER BY emp_no 
OFFSET 5 ROWS       -- Skip first 5 
FETCH NEXT 10 ROWS ONLY; -- limit to retrieve next 10 row after skiping rows
M Dänisch
quelle
0
SELECT TOP 10 * FROM table;

Ist das gleiche wie

SELECT * FROM table LIMIT 0,10;

Hier ist ein Artikel über die Implementierung von Limit in MsSQL. Es ist eine gute Lektüre, insbesondere die Kommentare.

Ólafur Waage
quelle
1
Danke, aber ich möchte die Aufnahme zwischen 10 und 20, gibt es eine Möglichkeit, das zu tun?
Bigballs
5
Diese Antwort antwortet nicht auf die Ursprungsfrage, aber es ist nützlich, wenn jemand wie ich wissen muss, wie man die ersten N Ergebnisse erhält und über Google usw. hierher kommt ...
brianlmerritt
0

In SQL ist kein LIMIT-Schlüsselwort vorhanden. Wenn Sie nur eine begrenzte Anzahl von Zeilen benötigen, sollten Sie ein TOP-Schlüsselwort verwenden, das einem LIMIT ähnelt.

Mitul Panchal
quelle
0

Wenn Ihre ID ein eindeutiger Kennungstyp ist oder Ihre ID in der Tabelle nicht sortiert ist, müssen Sie dies wie folgt tun.

select * from
(select ROW_NUMBER() OVER (ORDER BY (select 0)) AS RowNumber,* from table1) a
where a.RowNumber between 2 and 5



Der Code wird sein

Wählen Sie * aus dem Grenzwert 2,5
user3244012
quelle
0

Verwenden Sie dies besser in MSSQLExpress 2017.

SELECT * FROM
(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) as [Count], * FROM table1
) as a
WHERE [Count] BETWEEN 10 and 20;

- Geben Sie eine Spalte [Anzahl] und weisen Sie jeder Zeile eine eindeutige Zählung zu, ohne etwas zu bestellen. Wählen Sie dann erneut aus, wo Sie Ihre Grenzen angeben können. :)

user1308314
quelle
0

Eine der möglichen Möglichkeiten, um Ergebnisse wie unten zu erhalten, hoffe, dass dies helfen wird.

declare @start int
declare @end int
SET @start = '5000';  -- 0 , 5000 ,
SET @end = '10000'; -- 5001, 10001
SELECT * FROM ( 
  SELECT TABLE_NAME,TABLE_TYPE, ROW_NUMBER() OVER (ORDER BY TABLE_NAME) as row FROM information_schema.tables
 ) a WHERE a.row > @start and a.row <= @end
Pragnesh Karia
quelle
0

Einfacher Weg

MYSQL:

SELECT 'filds' FROM 'table' WHERE 'where' LIMIT 'offset','per_page'

MSSQL:

SELECT 'filds' FROM 'table' WHERE 'where' ORDER BY 'any' OFFSET 'offset' 
ROWS FETCH NEXT 'per_page' ROWS ONLY

ORDER BY ist obligatorisch

Turendu
quelle
-2

Wenn ich mich richtig erinnere (es ist schon eine Weile her, seit ich mit SQL Server getupft habe), können Sie möglicherweise Folgendes verwenden: (2005 und höher)

SELECT
    *
   ,ROW_NUMBER() OVER(ORDER BY SomeFields) AS [RowNum]
FROM SomeTable
WHERE RowNum BETWEEN 10 AND 20
Kris
quelle
SQL Server 2012: Nachricht 207, Ebene 16, Status 1, Zeile 5 Ungültiger Spaltenname 'RowNum'.
E-Info128
klingt wie Sie irgendwo einen Tippfehler in Ihrer Aussage haben. RowNum ist der Name, den wir dem Ausdruck zuweisen. Veröffentlichen Sie Ihr Problem mit der Quelle und die Community wird Ihnen helfen
Kris
Dies ist keine gültige Syntax. Sie können nicht auf WHEREeinen Alias verweisen, der in derselben Level- SELECTKlausel definiert ist.
Ypercubeᵀᴹ