LIMIT begrenzt die Anzahl der Zeilen
LIMIT ist der einfachste Hebel in SQL: Damit sagst du SQLite „gib mir höchstens so viele Zeilen". Setzt du es ans Ende eines SELECT, bekommst du maximal diese Anzahl an Ergebnissen zurück – nicht mehr, eventuell weniger, falls die Tabelle gar nicht genug Zeilen hergibt.
Du bekommst die ersten drei Zeilen zurück. Welche drei genau? Das ist der Haken — ohne ein ORDER BY liefert SQLite die Zeilen einfach in der Reihenfolge, die ihm gerade passt. Heute mag das die Einfügereihenfolge sein, morgen — nach einem Update oder einer Indexänderung — vielleicht schon nicht mehr. Ein LIMIT allein reicht völlig, wenn du dir nur "ein paar Beispieldaten" anzeigen lassen willst. Sobald aber die Reihenfolge eine Rolle spielt, musst du sie explizit festlegen.
Mit OFFSET Zeilen am Anfang überspringen
Kombinierst du LIMIT mit OFFSET, kannst du dir einen Ausschnitt aus der Mitte der Ergebnismenge holen — genau das, was du für sqlite pagination brauchst. OFFSET k überspringt die ersten k Zeilen, und LIMIT n gibt dir dann bis zu n Zeilen vom Rest zurück.
Das heißt: „Überspringe zwei Zeilen, gib die nächsten zwei zurück" – also Zeile 3 und 4 des sortierten Ergebnisses. Das mentale Modell dahinter: WHERE filtert, ORDER BY sortiert, OFFSET überspringt und LIMIT deckelt. Sie laufen genau in dieser Reihenfolge ab – und jeder Schritt zählt.
Pagination in SQLite braucht immer ein ORDER BY
Der häufigste Einsatzzweck von LIMIT und OFFSET ist die Pagination – also eine lange Liste in Seiten von z. B. 20 Zeilen aufteilen. Seite 1 ist LIMIT 20 OFFSET 0, Seite 2 ist LIMIT 20 OFFSET 20, und so weiter.
Zwei Dinge sind hier wichtig. Erstens: Das ORDER BY ist Pflicht — ohne explizite Sortierung hat "Seite 2" gar keine definierte Bedeutung, und die Zeilen können zwischen zwei Seitenaufrufen einfach durcheinander purzeln. Zweitens steht id als Tiebreaker im Sortierschlüssel. Wenn zwei Beiträge denselben created_at haben, brauchst du eine eindeutige Spalte, um die Reihenfolge deterministisch festzunageln — sonst tauschen die beiden ihre Plätze, und eine Zeile kann von einer Seite auf die andere rutschen.
Faustregel: Sortiere nach einer eindeutigen Spalte — oder nach deiner eigentlichen Sortierspalte plus einem eindeutigen Tiebreaker.
Kurzschreibweise: LIMIT n, m
SQLite kennt aus Kompatibilitätsgründen mit MySQL noch eine ältere Komma-Schreibweise: LIMIT offset, count. Bedeutet dasselbe wie LIMIT count OFFSET offset, aber die Reihenfolge der Werte ist genau umgedreht — und damit eine echte Stolperfalle beim Lesen.
-- Diese beiden sind äquivalent:
SELECT * FROM books LIMIT 10 OFFSET 20;
SELECT * FROM books LIMIT 20, 10; -- zuerst Offset, dann Anzahl
Die zweite Form ist zwar kompakter, aber sie führt regelmäßig zu Verwirrung, weil viele die erste Zahl als Anzahl interpretieren. Bleib lieber bei LIMIT n OFFSET k – das ist eindeutig und liest sich von vorne nach hinten weg.
OFFSET ohne LIMIT in SQLite: der LIMIT -1-Trick
Ein OFFSET allein funktioniert nicht – die SQLite-Grammatik verlangt, dass davor ein LIMIT steht. Wie sagt man also „überspringe die ersten 10 Zeilen und gib mir alles danach zurück"? Üblich ist hier LIMIT -1, was SQLite als „keine Obergrenze" auffasst.
Jeder negative LIMIT-Wert bewirkt dasselbe, aber -1 hat sich als Idiom durchgesetzt. Du siehst das vor allem in Skripten, die ein Ergebnis seitenweise durchgehen und für den letzten Batch eine "gib mir den Rest"-Abfrage brauchen.
Die Performance-Falle bei OFFSET
Eine Sache, die selten erwähnt wird, bis man selbst darüber stolpert: OFFSET sorgt nicht dafür, dass SQLite weniger Arbeit macht – es überspringt nur die Ausgabe. Für die Zeilen 10.001 bis 10.020 läuft die Engine intern trotzdem an den ersten zehntausend Zeilen vorbei, bevor sie überhaupt anfängt, Ergebnisse zurückzugeben. Kleine Offsets kosten nichts, aber sobald du in den Bereich von zehntausenden oder hunderttausenden kommst, wird es spürbar langsam.
Für tiefe Pagination ist die übliche Lösung die Keyset-Pagination: Statt "überspringe N Zeilen" merkst du dir den Sortierschlüssel der letzten Zeile und fragst nach "allen Zeilen nach dieser hier".
Jede Seite macht einen Index-Lookup, statt sich durch alle vorherigen Datensätze zu wühlen. Der Haken: Du kannst nicht direkt zu "Seite 47" springen — nur Schritt für Schritt vorwärts durch die Daten. Für Infinite-Scroll-Feeds und API-Cursors ist genau das gewünscht.
OFFSET-basierte Paginierung passt prima für Admin-Tabellen und überschaubare Ergebnismengen. Sobald die Datenmenge unbegrenzt wächst, solltest du auf Keyset-Pagination umsteigen.
Praxisbeispiel: SQLite Pagination mit LIMIT und OFFSET
Alles zusammen — eine paginierte Abfrage mit Filter, Sortierung und einem eindeutigen Tiebreaker:
Wir filtern auf die Office-Produkte, sortieren aufsteigend nach Preis und nehmen den Namen als zweites Sortierkriterium – dann schnappen wir uns die ersten beiden Treffer. Für Seite 2 änderst du einfach OFFSET 0 in OFFSET 2. Die Query ist kurz, aber jede Klausel verdient ihren Platz.
Weiter geht's mit DISTINCT
LIMIT legt fest, wie viele Zeilen zurückkommen; DISTINCT entscheidet, ob Duplikate überhaupt durchgelassen werden. Damit wandert die nächste Klausel aus dem SELECT-Werkzeugkasten ins Rampenlicht – und sie ist trügerisch einfach falsch einzusetzen. Genau darum geht's auf der nächsten Seite.
Häufig gestellte Fragen
Was macht LIMIT in SQLite?
LIMIT n begrenzt die Anzahl der Zeilen, die ein SELECT zurückliefert, auf höchstens n. Das passiert nach WHERE, GROUP BY und ORDER BY – du beschränkst also das fertige Ergebnis, nicht die Zeilen, die SQLite intern durchgeht. SELECT * FROM users LIMIT 10 gibt dir maximal zehn Zeilen zurück.
Wie spielen OFFSET und LIMIT in SQLite zusammen?
OFFSET k überspringt die ersten k Zeilen des Ergebnisses, bevor LIMIT zu zählen anfängt. LIMIT 10 OFFSET 20 liefert dir also die Zeilen 21 bis 30. SQLite muss die übersprungenen Zeilen intern aber trotzdem durchlaufen – genau deshalb werden große Offsets richtig langsam.
Kann man OFFSET in SQLite ohne LIMIT verwenden?
Direkt nicht – OFFSET ist nur als Teil einer LIMIT-Klausel erlaubt. Der Trick: LIMIT -1 OFFSET k. Die -1 heißt schlicht „keine Obergrenze", SQLite überspringt also k Zeilen und gibt dir den gesamten Rest zurück. Eine Eigenheit, die man im Hinterkopf haben sollte.
Warum brauchen paginierte Queries zwingend ein ORDER BY?
Ohne ORDER BY darf SQLite die Zeilen in beliebiger Reihenfolge zurückgeben, und diese Reihenfolge kann sich zwischen zwei Aufrufen ändern. Damit ist deine Pagination kaputt – dieselbe Zeile taucht plötzlich auf Seite 1 und Seite 3 auf oder verschwindet ganz. Kombiniere LIMIT/OFFSET deshalb immer mit einem ORDER BY auf einer stabilen, eindeutigen Spalte.