Contenido de esta guía
Respuesta rápida
FILTER (WHERE ...) limita las filas que recibe un agregado concreto. La fila puede seguir participando en otros agregados de la misma consulta.
COUNT(*) FILTER (WHERE estado = 'enviado')La idea clave es distinta de un WHERE general: WHERE elimina una fila de la entrada de toda la consulta; FILTER decide si esa fila entra en ese agregado.
Modelo mental: una entrada distinta para cada agregado
Imagina que cada agregado tiene su propia bandeja de entrada. COUNT(*) puede recibir las 18 filas de pedidos, mientras otro COUNT(*) FILTER (...) recibe únicamente los pedidos enviados. Ambos cálculos comparten la misma consulta, pero no necesariamente las mismas filas de entrada.
Patrón mental: filas de la consulta → condición de FILTER → agregado concreto.
Sintaxis básica
AGREGADO(expresion) FILTER (WHERE condicion)PostgreSQL documenta FILTER como parte de una expresión de agregado. SQLite también admite una cláusula FILTER y solo incluye en el agregado las filas cuya expresión sea verdadera.
Ejemplo: total de pedidos frente a pedidos enviados
Queremos tres medidas en una sola fila: todos los pedidos, cuántos están enviados y cuánto importe acumulan únicamente los enviados.
SELECT COUNT(*) AS pedidos,
COUNT(*) FILTER (WHERE estado = 'enviado') AS enviados,
ROUND(SUM(total) FILTER (WHERE estado = 'enviado'), 2) AS importe_enviado
FROM pedidos;| pedidos | enviados | importe_enviado |
|---|---|---|
| 18 | 9 | 1818,70 |
Las 18 filas llegan a COUNT(*). Solo las 9 filas con estado enviado llegan al segundo COUNT y al SUM filtrado.
FILTER vs WHERE, HAVING y CASE
| Herramienta | Qué decide | Momento útil |
|---|---|---|
WHERE | Qué filas llegan a la consulta antes de agrupar | La condición debe afectar a todos los cálculos |
FILTER | Qué filas recibe un agregado concreto | Necesitas varias métricas condicionales en la misma fila |
HAVING | Qué grupos permanecen después de agregar | Filtras grupos por un resultado agregado |
CASE dentro del agregado | Qué valor aporta cada fila al cálculo | Quieres un patrón explícito y ampliamente portable |
El patrón ya explicado en SUM(CASE WHEN ...) puede resolver muchos de los mismos problemas. FILTER hace visible que la condición pertenece al agregado, pero no debes asumir que todos los motores aceptan la misma sintaxis.
FILTER también funciona dentro de GROUP BY
SELECT cliente_id,
COUNT(*) AS pedidos,
COUNT(*) FILTER (WHERE estado = 'enviado') AS enviados
FROM pedidos
GROUP BY cliente_id
ORDER BY cliente_id;Cada fila de salida representa un cliente. Dentro de cada grupo, el primer conteo usa todas las filas y el segundo solo las enviadas.
Errores frecuentes
Usar WHERE cuando solo una métrica debía filtrarse
Si escribes WHERE estado = 'enviado', también reduces el COUNT(*) total. Usa FILTER cuando el filtro pertenezca a una medida y no al conjunto completo.
Confundir FILTER con HAVING
FILTER selecciona entradas de un agregado. HAVING se evalúa sobre los grupos ya formados y decide si una fila agregada permanece en el resultado.
Dar por portable una sintaxis del motor
PostgreSQL y SQLite documentan FILTER. Si tu proyecto apunta a otro motor, verifica su sintaxis; CASE dentro del agregado sigue siendo una alternativa clara para expresar la condición.
Práctica guiada
Separa pedidos de 200 € o más
Devuelve una sola fila con pedidos_200_mas y pedidos_menos_200 usando dos COUNT(*) FILTER (...).
Criterio de éxito: el resultado es 5 | 13.
COUNT(*) para cada condición.total >= 200.FILTER (WHERE ...) después de cada agregado.Solución razonada
SELECT
COUNT(*) FILTER (WHERE total >= 200) AS pedidos_200_mas,
COUNT(*) FILTER (WHERE total < 200) AS pedidos_menos_200
FROM pedidos;| pedidos_200_mas | pedidos_menos_200 |
|---|---|
| 5 | 13 |
Las dos condiciones son excluyentes para los totales conocidos y juntas cubren las 18 filas.
Compatibilidad
PostgreSQL incluye FILTER (WHERE ...) en la sintaxis de sus expresiones de agregado. SQLite documenta la misma idea en su sintaxis de funciones agregadas. Para otros motores, consulta su documentación antes de copiar esta forma literalmente.
Qué debes recordar
FILTERmodifica la entrada de un agregado concreto.WHEREfiltra las filas para la consulta completa.HAVINGfiltra grupos después de agregar.- Es especialmente útil cuando una fila de salida contiene varias métricas con condiciones diferentes.
SUM(CASE WHEN ...)sigue siendo un patrón importante cuando buscas una alternativa explícita y portable.