COUNT
La función COUNT es probablemente la función de agregación que más usarás en MySQL. Sirve para contar filas en una tabla o en el resultado de una consulta. Parece simple, pero tiene matices importantes que conviene entender bien: la diferencia entre COUNT(*), COUNT(columna) y COUNT(expresion) determina qué filas se cuentan y cuáles se ignoran.
Sintaxis
COUNT(*)
COUNT(expresion)
COUNT(ALL expresion)COUNT(*) cuenta todas las filas del grupo, incluyendo aquellas que contienen valores NULL. COUNT(expresion) cuenta solo las filas donde la expresión no es NULL. La palabra clave ALL es el comportamiento por defecto y raramente se escribe de forma explícita.
Cuando usas COUNT sin GROUP BY, MySQL trata toda la tabla como un único grupo y devuelve una sola fila con el resultado.
Comportamiento básico
COUNT(*) cuenta todas las filas
La forma más directa es contar el total de registros en una tabla:
SELECT COUNT(*) AS total_productos
FROM productos;| total_productos |
|---|
| 50 |
COUNT(*) no examina el contenido de las columnas. Simplemente cuenta las filas que existen, sin importar si alguna columna contiene NULL. Internamente, MySQL optimiza COUNT(*) de forma especial: con el motor InnoDB utiliza el índice secundario más pequeño para hacer el conteo, lo que es más eficiente que escanear toda la tabla.
COUNT(columna) ignora los NULL
Supongamos que la tabla empleados tiene una columna telefono donde algunos empleados no han proporcionado su número:
SELECT
COUNT(*) AS total_empleados,
COUNT(telefono) AS con_telefono
FROM empleados;| total_empleados | con_telefono |
|---|---|
| 25 | 19 |
Hay 25 empleados en total, pero solo 19 tienen un número de teléfono registrado. COUNT(telefono) descartó automáticamente las 6 filas donde telefono es NULL. Esta diferencia entre COUNT(*) y COUNT(columna) es fundamental y fuente de errores si no la tienes presente.
Caso práctico: conteo con GROUP BY
El verdadero poder de COUNT aparece cuando lo combinas con GROUP BY para obtener conteos por categoría. Veamos cuántos productos tiene cada categoría:
SELECT
c.nombre AS categoria,
COUNT(*) AS total_productos
FROM productos p
JOIN categorias c ON p.categoria_id = c.id
GROUP BY c.nombre
ORDER BY total_productos DESC;| categoria | total_productos |
|---|---|
| Smartphones | 12 |
| Portátiles | 8 |
| Accesorios electrónicos | 7 |
| Ropa hombre | 6 |
| Ropa mujer | 6 |
| Hogar | 5 |
| Deportes | 4 |
| Libros | 2 |
Cada fila del resultado corresponde a un grupo distinto. MySQL agrupa las filas por c.nombre y luego aplica COUNT(*) dentro de cada grupo.
Caso práctico: conteo con WHERE
Puedes combinar COUNT con WHERE para contar solo las filas que cumplan una condición. Por ejemplo, contar los pedidos realizados en enero de 2026:
SELECT COUNT(*) AS pedidos_enero
FROM pedidos
WHERE fecha_pedido BETWEEN '2026-01-01' AND '2026-01-31';| pedidos_enero |
|---|
| 134 |
También puedes combinar WHERE y GROUP BY para obtener conteos filtrados por grupo. Veamos cuántos pedidos completados tiene cada cliente:
SELECT
cl.nombre,
cl.apellidos,
COUNT(*) AS pedidos_completados
FROM pedidos p
JOIN clientes cl ON p.cliente_id = cl.id
WHERE p.estado = 'completado'
GROUP BY cl.id, cl.nombre, cl.apellidos
ORDER BY pedidos_completados DESC
LIMIT 5;| nombre | apellidos | pedidos_completados |
|---|---|---|
| María | García López | 8 |
| Carlos | Rodríguez Martín | 7 |
| Ana | Martínez Ruiz | 6 |
| Pedro | Sánchez Gómez | 5 |
| Laura | Fernández Díaz | 5 |
El WHERE filtra las filas antes de que se formen los grupos, por lo que COUNT(*) solo cuenta los pedidos que ya pasaron el filtro.
Caso práctico: COUNT con expresiones
Puedes pasar una expresión a COUNT para contar filas que cumplen una condición sin necesidad de WHERE. Esto es útil cuando quieres varios conteos en la misma consulta:
SELECT
COUNT(*) AS total_productos,
COUNT(CASE WHEN precio > 1000 THEN 1 END) AS productos_premium,
COUNT(CASE WHEN stock = 0 THEN 1 END) AS sin_stock
FROM productos;| total_productos | productos_premium | sin_stock |
|---|---|---|
| 50 | 8 | 3 |
La expresión CASE WHEN precio > 1000 THEN 1 END devuelve 1 cuando se cumple la condición y NULL cuando no se cumple (el ELSE NULL es implícito). Como COUNT ignora los NULL, solo cuenta las filas donde la condición es verdadera.
Manejo de NULL
Entender cómo COUNT maneja los NULL es crucial. Recapitulemos con un ejemplo claro:
SELECT
COUNT(*) AS todas_las_filas,
COUNT(descuento) AS con_descuento,
COUNT(*) - COUNT(descuento) AS sin_descuento
FROM productos;| todas_las_filas | con_descuento | sin_descuento |
|---|---|---|
| 50 | 12 | 38 |
La resta entre COUNT(*) y COUNT(descuento) te da el número de productos donde descuento es NULL. Este patrón es una forma práctica de contar valores nulos sin usar una subconsulta.
Combinación con otras funciones
COUNT se combina frecuentemente con HAVING para filtrar grupos según su conteo:
SELECT
c.nombre AS categoria,
COUNT(*) AS total_productos
FROM productos p
JOIN categorias c ON p.categoria_id = c.id
GROUP BY c.nombre
HAVING COUNT(*) >= 6
ORDER BY total_productos DESC;| categoria | total_productos |
|---|---|
| Smartphones | 12 |
| Portátiles | 8 |
| Accesorios electrónicos | 7 |
| Ropa hombre | 6 |
| Ropa mujer | 6 |
HAVING se aplica después de la agrupación, a diferencia de WHERE que se aplica antes. Por eso puedes usar funciones de agregación en HAVING pero no en WHERE.
También puedes usar COUNT dentro de subconsultas para filtrar por conteo:
SELECT nombre, apellidos
FROM clientes
WHERE id IN (
SELECT cliente_id
FROM pedidos
GROUP BY cliente_id
HAVING COUNT(*) > 5
);Esta consulta obtiene los clientes que tienen más de 5 pedidos.
Rendimiento de COUNT(*) con InnoDB
En versiones anteriores de MySQL con el motor MyISAM, COUNT(*) sin WHERE era instantáneo porque MyISAM almacenaba el conteo total de filas como metadato. Con InnoDB, que es el motor por defecto desde MySQL 5.5, esto ya no es así: InnoDB necesita recorrer un índice para contar las filas, porque el sistema de transacciones MVCC implica que distintas transacciones pueden ver distintas cantidades de filas. Si trabajas con tablas de millones de registros y necesitas un conteo aproximado frecuente, considera cachear el resultado o usar SHOW TABLE STATUS para obtener una estimación rápida.
Practica con COUNT
Usa el editor para contar filas con distintas condiciones:
En el siguiente artículo veremos COUNT DISTINCT para contar valores únicos.
Escrito por Eduardo Lázaro
