Filtrado de agregación
Having
Una vez que se obtiene información calculada sobre grupos de filas mediante el group by, se pueden filtrar estos resultados y mostrar sólo aquellos que nos interesen mediante la cláusula having. Having es a group by lo mismo que where a select-from.
Al igual que la cláusula where selecciona filas, la cláusula having selecciona grupos; si, en where, la condición que se especifica afecta a las filas de toda la tabla, group by efectúa cálculos en función de esa selección previa, y da como resultado una tabla con la información calculada para cada grupo dentro de esa selección. Sobre esta última, having eliminaría aquellas filas que no cumplen la condición.
Where filtra los datos almacenados en la tabla y
having la información calculada.
Podemos entender el proceso de una consulta con group by-having como la ejecución previa de la parte select-from-where y, a partir de este resultado intermedio, la obtención de la información calculada con group by y, finalmente, el filtrado con having.
¿Cuántas asignaturas imparte cada profesor?
select p.dni, nombre, count(*) asignaturas
from profesores p, imparte i
where p.dni = i.dni
group by p.dni, nombre
¿Cuántas asignaturas imparten los profesores con 2 o más asignaturas?
select p.dni, nombre, count(*) asignaturas
from profesores p, imparte i
where p.dni = i.dni
group by p.dni, nombre
having count(*) >= 2
Sin tener en cuenta la asignatura FBD, ¿cuántas asignaturas imparten los profesores con 2 o más asignaturas?
select p.dni, nombre, count(*) asignaturas
from profesores p, imparte i
where p.dni = i.dni
and asignatura != 'FBD'
group by p.dni, nombre
having count(*) >= 2
Paso a paso:
where ha eliminado las tuplas de imparte de código de asignatura FBD.
group by calcula, para cada profesor, el número de asignaturas que imparte. Puesto que no contamos FBD, Eva Gómez solo imparte, igual que Rafael Romero, una única asignatura.
having elimina del resultado del paso anterior todas aquellas tuplas con un valor en la cuenta de filas menor que 2. El resultado es vacío puesto que ninguno de los grupos supera la condición.
Ninguna fila seleccionada.
La condición del having no es necesariamente sobre el cálculo a mostrar, como se puede ver en el siguiente ejemplo.
¿Cuántas asignaturas imparte cada profesor en el caso de que la suma de créditos sea mayor que 5?
select p.dni, nombre, count(*) asignaturas
from profesores p, imparte i, asignaturas a
where p.dni = i.dni and a.codigo = i.asignatura
group by p.dni, nombre
having sum(creditos) > 5
MariaDB/MySQL permite alejarse del SQL estándar
Nuestro servidor está configurado con @@SQL_MODE = 'ONLY_FULL_GROUP_BY'.
Si estás trabajando contra tu propio servidor local, es posible que este modo SQL no esté configurado así, y sí darán resultado. Puedes modificar este comportamiento con set sql_mode = ''. Cuando cierres la conexión y te identifiques de nuevo en el servidor, la variable volverá a su valor anterior.
Hay que tener cuidado con una característica de MariaDB/MySQL que depende también de cómo esté configurado el servidor. El caso es que podría darse el caso de que MariaDB/MySQL acepte la siguiente orden en la que hemos omitido la columna nombre del group by:
DNI y nombre del coordinador y cuántas asignaturas coordina.
set @modo = @@SQL_MODE; -- para poder restaurar la configuración al final
set sql_mode = '';
select dni, nombre, count(*) coordina
from asignaturas a, coordinadores c
where c.asig = a.codigo
group by dni;
set SQL_MODE = @modo; -- restaurada configuración
En este caso, no hay problema puesto que para cada dni hay un único nombre, dni es el identificador de los coordinadores, pero no siempre es así. Como en muchas otras cosas, MariaDB/MySQL ofrece funcionalidades propias que el usuario puede elegir o no, pero alejarse del estándar dificulta la posibilidad de migrar a otros sistemas de gestión de base de datos. MariaDB/MySQL deja en manos del que realiza la consulta el que tenga cuidado con el criterio de agrupación que utiliza asegurándose de que las columnas omitidas no van a alterar el resultado. Hay autores que defienden este "alejamiento" del estándar, como Roland Bouman.
Otra característica que MySQL permite por defecto es utilizar having sin group by:
set @modo = @@SQL_MODE; -- para poder restaurar la configuración al final
set sql_mode = '';
select * from asignaturas
having creditos > 3;
set SQL_MODE = @modo; -- restaurada configuración
La idea que subyace en esta "permisividad" es que where no permite utilizar funciones de agregado mientras que having sí. Nuevamente, esta extensión de MariaDB/MySQL no es aceptada por todos los gestores de BD.
En cualquier caso, no recomendamos estas prácticas, al menos en un contexto de aprendizaje básico, ni tampoco las aceptaremos en la evaluación de este tipo de ejercicios.