LIMIT pone un tope al número de filas
LIMIT es la perilla más sencilla de SQL: le dice a SQLite "dame como mucho esta cantidad de filas". Lo añades al final de un SELECT y recibirás hasta ese número de resultados — ni una más, y posiblemente menos si la tabla no tiene suficientes filas para llenar el cupo.
Te devuelve las tres primeras filas. ¿Cuáles tres exactamente? Ahí está la trampa: sin un ORDER BY, SQLite escoge el orden que más le convenga. Hoy puede ser el orden de inserción; mañana, tras un update o un cambio de índice, puede que no. Usar LIMIT por sí solo está bien para un "muéstrame una muestra", pero en cuanto el orden importe, hay que dejarlo explícito.
OFFSET: saltar filas en SQLite
Combina LIMIT con OFFSET y podrás pedir una porción intermedia del resultado. OFFSET k descarta las primeras k filas; luego LIMIT n devuelve hasta n filas de las que quedan.
Eso significa "salta dos filas y devuelve las dos siguientes" — es decir, las filas 3 y 4 del resultado ya ordenado. El modelo mental es claro: WHERE filtra, ORDER BY ordena, OFFSET salta y LIMIT recorta. Se ejecutan en ese orden, y cada uno cumple su función.
Paginación en SQLite: siempre con ORDER BY
El uso más típico de LIMIT y OFFSET es la paginación en SQLite, es decir, partir una lista larga en páginas de, por ejemplo, 20 filas cada una. La página 1 sería LIMIT 20 OFFSET 0, la página 2 sería LIMIT 20 OFFSET 20, y así sucesivamente.
Hay dos detalles importantes. Primero, el ORDER BY no es opcional: sin él, hablar de "página 2" no tiene sentido, ya que las filas pueden cambiar de orden entre una consulta y otra. Segundo, la clave de ordenación incluye id como desempate. Si dos posts comparten el mismo created_at, necesitas una columna única que les dé un orden determinista; de lo contrario, sus posiciones pueden intercambiarse y una fila podría colarse entre páginas.
Regla práctica: ordena por algo único, o bien por tu columna de ordenación más una columna única que actúe de desempate.
Una forma abreviada: LIMIT n, m
SQLite admite una sintaxis antigua con coma por compatibilidad con MySQL: LIMIT offset, count. Significa exactamente lo mismo que LIMIT count OFFSET offset, pero con el orden invertido, lo que se presta fácilmente a confusión.
-- Estas dos son equivalentes:
SELECT * FROM books LIMIT 10 OFFSET 20;
SELECT * FROM books LIMIT 20, 10; -- primero el desplazamiento, luego la cantidad
La segunda forma es más corta, pero suele confundir a quien espera que el primer número sea la cantidad. Quédate con LIMIT n OFFSET k: es explícito y se lee de izquierda... bueno, en orden natural.
OFFSET sin LIMIT: el truco de LIMIT -1
OFFSET no se puede usar solo: la gramática de SQLite exige que vaya siempre detrás de un LIMIT. Entonces, ¿cómo le dices "sáltate las primeras 10 filas y dame todo lo demás"? La convención es usar LIMIT -1, que SQLite interpreta como "sin límite superior".
Cualquier LIMIT negativo hace lo mismo, pero -1 es la convención establecida. Lo verás sobre todo en scripts que recorren un resultado por páginas y quieren una consulta tipo "dame el resto" para el último lote.
La trampa de rendimiento de OFFSET
Aquí está lo que nadie menciona hasta que te topas con ello: OFFSET no hace que SQLite se ahorre trabajo, solo hace que se ahorre salida. Para devolver las filas de la 10.001 a la 10.020, el motor sigue recorriendo internamente las primeras diez mil filas antes de empezar a emitir resultados. Los offsets pequeños salen gratis; los offsets de decenas o cientos de miles se vuelven lentos de forma evidente.
Para paginación profunda, la solución habitual es la paginación por clave (keyset pagination): en vez de "saltar N filas", guardas la clave de orden de la última fila y pides "las filas posteriores a esta".
Cada página hace una búsqueda por índice en vez de recorrer todo lo anterior. ¿La contra? No puedes saltar a la "página 47", solo avanzar a través de los datos. Para feeds de scroll infinito y cursores de API, eso es justo lo que quieres.
La paginación con OFFSET está bien para tablas de administración y conjuntos de resultados pequeños. Para cualquier cosa que crezca sin límite, tira de paginación por keyset.
Un ejemplo completo
Juntando todas las piezas: una consulta paginada con filtrado, ordenamiento y un desempate determinista:
Filtramos los productos de oficina, ordenamos por precio ascendente usando el nombre como criterio de desempate y nos quedamos con los dos primeros. Para la página 2, basta con cambiar OFFSET 0 por OFFSET 2. La consulta es corta, pero cada cláusula cumple su función.
Lo que viene: DISTINCT
LIMIT controla cuántas filas se devuelven; DISTINCT controla si se devuelven duplicados o no. Es la siguiente cláusula del kit de herramientas de SELECT, y es engañosamente fácil de usar mal — eso lo vemos en la siguiente página.
Preguntas frecuentes
¿Qué hace LIMIT en SQLite?
LIMIT n hace que un SELECT devuelva como mucho n filas. Se aplica después de WHERE, GROUP BY y ORDER BY, así que estás limitando el resultado final, no las filas que la consulta recorre internamente. Por ejemplo, SELECT * FROM users LIMIT 10 devuelve hasta diez filas.
¿Cómo funciona OFFSET junto con LIMIT en SQLite?
OFFSET k salta las primeras k filas del resultado antes de que LIMIT empiece a contar. Es decir, LIMIT 10 OFFSET 20 te devuelve las filas de la 21 a la 30. Eso sí, SQLite tiene que recorrer internamente esas filas que descarta, y por eso los offsets grandes acaban siendo lentos.
¿Se puede usar OFFSET sin LIMIT en SQLite?
Directamente no: OFFSET solo es válido como parte de una cláusula LIMIT. El truco habitual es escribir LIMIT -1 OFFSET k, donde -1 significa 'sin tope', así que SQLite salta k filas y devuelve todo lo que viene después. Es una rareza que conviene tener fichada.
¿Por qué las consultas paginadas necesitan ORDER BY?
Sin ORDER BY, SQLite puede devolver las filas en el orden que le dé la gana, y ese orden puede cambiar entre una consulta y otra. La paginación se rompe: la misma fila puede salir en la página 1 y en la página 3, o desaparecer sin más. Acompaña siempre LIMIT/OFFSET con un ORDER BY sobre una columna estable y única.