Recuerda que las funciones agregadas son aquellas que trabajan con varias filas de datos a la vez y devuelven un solo resultado. En PostgreSQL vas a usar muy a menudo las siguientes funciones agregadas:
SUM()— suma de datos.AVG()— cálculo del valor promedio.MIN()— búsqueda del valor mínimo.MAX()— búsqueda del valor máximo.COUNT()— conteo de filas.
A primera vista, todo es fácil: le pasas una columna o una expresión a la función y obtienes el resultado. Pero, ¿qué pasa si en la columna aparece un NULL?
Comportamiento de NULL en agregados: resumen rápido
Aquí es donde empieza lo interesante:
SUM()yAVG()ignoranNULL. Si al menos un registro tiene valorNULL, simplemente no se tiene en cuenta en los cálculos. Tiene sentido, ¿no? ¿Cómo va a crecer la suma si alguien "no vino a la fiesta"? ¿O cómo calcular el promedio si falta un valor?MIN()yMAX()también saltan losNULL. Encuentran el valor mínimo o máximo solo entre los datos que no sonNULL. Así que, si buscas el empleado más joven y alguien no rellenó la fecha de nacimiento,NULLno va a ganar.COUNT(*)cuenta todas las filas, incluso las que tienenNULL. PeroCOUNT(column)solo cuenta las filas donde la columna indicada tiene valor, o sea,NULLse ignora.
Vamos a verlo con ejemplos.
Ejemplos de uso de funciones agregadas con NULL
Aquí tienes la tabla students_scores, que contiene las notas de los estudiantes en un test:
| student_id | name | score |
|---|---|---|
| 1 | Alicia | 85 |
| 2 | Bob | NULL |
| 3 | Charlie | 92 |
| 4 | Dana | NULL |
| 5 | Elena | 74 |
Ahora vamos a lanzar unas consultas y analizar sus resultados:
- Suma de todas las notas:
SUM()
SELECT SUM(score) AS total_score
FROM students_scores;
Resultado:
| total_score |
|---|
| 251 |
Como ves, los valores NULL simplemente no participaron en la suma. Para Alicia (85), Charlie (92) y Elena (74) la suma es 251. Bob y Dana se quedaron fuera.
- Nota promedio:
AVG()
SELECT AVG(score) AS average_score
FROM students_scores;
Resultado:
| average_score |
|---|
| 83.67 |
Otra vez, los NULL fueron ignorados y el promedio se calculó solo para quienes tienen nota: (85 + 92 + 74) / 3 = 83.67.
- Nota mínima y máxima:
MIN()yMAX()
SELECT
MIN(score) AS min_score,
MAX(score) AS max_score
FROM students_scores;
Resultado:
| min_score | max_score |
|---|---|
| 74 | 92 |
Aquí también es fácil: los valores NULL otra vez se ignoran, y la nota mínima es 74 y la máxima es 92.
- Conteo de filas:
COUNT(*)vsCOUNT(column)
SELECT
COUNT(*) AS total_rows,
COUNT(score) AS non_null_scores
FROM students_scores;
Resultado:
| total_rows | non_null_scores |
|---|---|
| 5 | 3 |
COUNT(*)contó todas las filas, incluso dondescoreesNULL.COUNT(score)solo contó las filas donde la columnascoretiene valor.
Casos prácticos
Vamos con algunos ejemplos prácticos.
Ejemplo 1: Contar empleados con y sin salario indicado
Supón que tienes una tabla employees con los salarios.
| id | name | salary |
|---|---|---|
| 1 | Alex Lin | 50000 |
| 2 | Maria Chi | NULL |
| 3 | Anna Song | 60000 |
| 4 | Otto Art | NULL |
| 5 | Liam Park | 55000 |
Queremos saber cuántos empleados han indicado su salario y cuántos no.
SELECT
COUNT(*) AS total_employees,
COUNT(salary) AS employees_with_salary,
COUNT(*) - COUNT(salary) AS employees_without_salary
FROM employees;
Aquí:
COUNT(*)devuelve el número total de empleados.COUNT(salary)cuenta cuántos empleados han indicado su salario.- Para saber cuántos no lo han hecho, solo restamos un valor al otro.
Resultado
| total_employees | employees_with_salary | employees_without_salary |
|---|---|---|
| 5 | 3 | 2 |
Ejemplo 2: Calcular el precio promedio de productos con datos faltantes
Eres dueño de una tienda mágica y en la tabla products hay una columna price, pero algunos productos aún no tienen precio.
| id | name | price |
|---|---|---|
| 1 | Magic Wand | 150 |
| 2 | Enchanted Cloak | NULL |
| 3 | Potion Bottle | 75 |
| 4 | Spell Book | 200 |
| 5 | Crystal Ball | NULL |
Necesitas saber el precio promedio solo para los productos que sí tienen precio.
SELECT AVG(price) AS average_price
FROM products;
Resultado:
| average_price |
|---|
| 141.6667 |
Si quieres poner un precio por defecto para los productos sin precio (por ejemplo, ponerlo a 0), puedes usar la función COALESCE() que veremos en la próxima lección.
Ejemplo 3: Encontrar la edad mínima y máxima de los estudiantes
En la tabla students se guarda la edad de los alumnos, pero para algunos no se conoce la edad (NULL).
| id | name | age |
|---|---|---|
| 1 | Alex Lin | 20 |
| 2 | Maria Chi | NULL |
| 3 | Anna Song | 19 |
| 4 | Otto Art | 22 |
| 5 | Liam Park | NULL |
Queremos saber quién es el estudiante más joven y el mayor.
SELECT
MIN(age) AS youngest_student,
MAX(age) AS eldest_student
FROM students;
Resultado:
| youngest_student | eldest_student |
|---|---|
| 19 | 22 |
Esta consulta devuelve la edad mínima y máxima solo para los estudiantes que sí tienen edad indicada. NULL otra vez se ignora.
Detalles y trampas
Cuando trabajes con NULL en agregados, es importante recordar lo siguiente:
- En la suma
SUM()y el promedioAVG(), losNULLno se tienen en cuenta. Puedes usar esto para no meter valores "vacíos" en los cálculos. - Si necesitas contar filas con
NULLen la columna, usaCOUNT(*). - Al usar
MIN()oMAX(),NULLno afecta el resultado. Pero si toda la columna es soloNULL, el resultado también seráNULL.
Consejos para trabajar con NULL
- Ten en cuenta el contexto de tu consulta. Es importante entender si necesitas tener en cuenta los
NULLen tu consulta. A veces, como conAVG(), ignorarlos es justo lo que quieres. Otras veces, como al contar el total, es importante incluir también las filas conNULL. - Usa
COALESCE()si hace falta. Si necesitas reemplazarNULLpor un valor por defecto en los cálculos, la funciónCOALESCE()será tu aliada (pero eso lo veremos en la próxima lección). - No confundas
COUNT(*)yCOUNT(column). Este es un error clásico de principiantes. El primero cuenta filas, el segundo solo filas con valores no nulos.
Ahora ya sabes cómo el silencioso NULL puede afectar a los agregados. Este conocimiento te ayudará a evitar sorpresas y a usar NULL a tu favor. En la próxima lección veremos la potente función COALESCE() para manejar NULL aún mejor.
GO TO FULL VERSION