W3docs

PHP MySQL SELECT con LIMIT: Guía completa

Aprende a usar la cláusula LIMIT en MySQL con PHP para recuperar un número específico de registros y construir paginación segura con sentencias preparadas.

En una base de datos a menudo solo se necesita una porción de una tabla — las diez publicaciones más recientes, la primera página de resultados de búsqueda, un único "mejor puntuador" — en lugar de todas las filas. La cláusula LIMIT en una sentencia SELECT de MySQL limita la cantidad de filas que devuelve la consulta. Combinada con un OFFSET, es la base de la paginación: servir grandes conjuntos de resultados de a una página a la vez, en lugar de cargar miles de filas en memoria.

Este capítulo cubre la sintaxis de LIMIT, el OFFSET para omitir filas, cómo construir paginación de forma segura con sentencias preparadas y los errores comunes que suelen cometerse. Se asume que ya sabes conectarte a MySQL y ejecutar un SELECT básico.

Sintaxis de SELECT con LIMIT

La forma básica establece un número máximo de filas a retornar:

SELECT column1, column2, ... FROM table_name LIMIT row_count;

Para también omitir filas desde el inicio del conjunto de resultados, agrega un offset. MySQL admite dos formas equivalentes:

SELECT ... FROM table_name LIMIT offset, row_count;   -- offset first
SELECT ... FROM table_name LIMIT row_count OFFSET offset;  -- explicit OFFSET

Qué significa cada parte:

  • row_count — el número máximo de filas a retornar.
  • offset — cuántas filas omitir antes de comenzar a retornar filas. El offset es basado en cero, por lo que OFFSET 0 comienza en la primera fila.
  • LIMIT 10, 5 retorna 5 filas comenzando después de las primeras 10 (es decir, las filas 11–15). La misma consulta se lee de forma más natural como LIMIT 5 OFFSET 10.

LIMIT sin ORDER BY no es determinista. Sin un ORDER BY explícito, MySQL puede devolver las filas en cualquier orden, por lo que "las primeras 2 filas" pueden diferir entre ejecuciones. Siempre combina LIMIT con ORDER BY cuando el orden de las filas importa.

Ejemplo: recuperar las primeras filas

Considera una tabla llamada students:

+----+---------+--------+-------+
| id | name    | class  | marks |
+----+---------+--------+-------+
|  1 | John    | 10     | 90    |
|  2 | Michael | 9      | 85    |
|  3 | Jessica | 8      | 80    |
|  4 | Sarah   | 10     | 88    |
|  5 | David   | 9      | 72    |
+----+---------+--------+-------+

Para obtener los primeros dos estudiantes (ordenados por id para que el resultado sea estable):

<?php
$conn = mysqli_connect("localhost", "username", "password", "database");

$query = "SELECT id, name, class, marks FROM students ORDER BY id LIMIT 2";
$result = mysqli_query($conn, $query);

while ($row = mysqli_fetch_assoc($result)) {
    echo "ID: {$row['id']} Name: {$row['name']} Class: {$row['class']} Marks: {$row['marks']}<br>";
}

mysqli_close($conn);
?>

Salida:

ID: 1 Name: John Class: 10 Marks: 90
ID: 2 Name: Michael Class: 9 Marks: 85

Nótese el uso de mysqli_fetch_assoc() (solo array asociativo) en lugar de mysqli_fetch_array(), que devuelve tanto claves numéricas como de cadena y por tanto asigna el doble de memoria para los mismos datos.

Omitir filas con OFFSET

Para obtener la segunda página de dos estudiantes — filas 3 y 4 — omite las primeras dos:

<?php
$conn = mysqli_connect("localhost", "username", "password", "database");

$query = "SELECT id, name, marks FROM students ORDER BY id LIMIT 2 OFFSET 2";
$result = mysqli_query($conn, $query);

while ($row = mysqli_fetch_assoc($result)) {
    echo "ID: {$row['id']} Name: {$row['name']} Marks: {$row['marks']}<br>";
}

mysqli_close($conn);
?>

Salida:

ID: 3 Name: Jessica Marks: 80
ID: 4 Name: Sarah Marks: 88

Construir paginación de forma segura

Para una paginación real, el número de página proviene de la entrada del usuario (una URL como ?page=3), por lo que el offset nunca debe concatenarse directamente en SQL. Usa una sentencia preparada con parámetros enteros enlazados:

<?php
$conn = mysqli_connect("localhost", "username", "password", "database");

$perPage = 2;
$page    = max(1, (int) ($_GET['page'] ?? 1)); // force a positive integer
$offset  = ($page - 1) * $perPage;

$stmt = mysqli_prepare(
    $conn,
    "SELECT id, name, marks FROM students ORDER BY id LIMIT ? OFFSET ?"
);
mysqli_stmt_bind_param($stmt, "ii", $perPage, $offset); // "ii" = two integers
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);

while ($row = mysqli_fetch_assoc($result)) {
    echo "ID: {$row['id']} Name: {$row['name']} Marks: {$row['marks']}<br>";
}

mysqli_close($conn);
?>

Convertir la página a (int) y enlazarla como entero ("ii") previene la inyección SQL, ya que LIMIT/OFFSET solo aceptan números de todas formas.

Para mostrar "Página 3 de N", también necesitas el conteo total de filas. Ejecuta una consulta COUNT(*) separada y divide por el tamaño de página:

$total = (int) mysqli_fetch_row(
    mysqli_query($conn, "SELECT COUNT(*) FROM students")
)[0];
$pageCount = (int) ceil($total / $perPage); // 5 rows / 2 per page = 3 pages

Errores comunes

  • Sin ORDER BY, sin garantía. Como se indicó, LIMIT solo devuelve un fragmento estable cuando se combina con un ORDER BY en una columna única (o con desempate).
  • Los offsets grandes son lentos. LIMIT 20 OFFSET 100000 hace que MySQL escanee y descarte 100.000 filas. Para paginación profunda, prefiere la paginación por keysetWHERE id > :lastSeenId ORDER BY id LIMIT 20 — que salta directamente al lugar correcto usando el índice. Ver WHERE.
  • OFFSET no puede usarse solo. MySQL requiere un LIMIT siempre que uses OFFSET. Para omitir filas y retornar "el resto", usa un límite enorme: LIMIT 18446744073709551615 OFFSET 10.
  • Las páginas se indexan internamente desde cero. Un error de desfase frecuente es olvidar que la página 1 corresponde a OFFSET 0, de ahí el ($page - 1) * $perPage del ejemplo anterior.

Práctica

Práctica
¿Cuál es el propósito de la palabra clave 'LIMIT' en MySQL?
¿Cuál es el propósito de la palabra clave 'LIMIT' en MySQL?
Was this page helpful?