Agrupar
GROUP BY
GROUP BY
permite "repartir" (agrupar) los registros leídos de una tabla en base a los valores de un campo elegido.
Como analogía, es como si este comando creara varias tablas paralelas que se reparten las filas entre sí.
Una vez reordenadas las filas se aplica la función de agregación elegida de manera paralela para cada grupo,
obteniéndose un resultado separado para cada grupo.
Uso básico
Supóngase el ejemplo de la tabla Products
,
la cual tiene 77 productos distintos.
Si se buscara calcular el precio promedio de los productos según su proveedor:
-- ordena los promedios de precios por proveedor
SELECT SupplierID, ROUND(AVG(Price),2) AS promedio FROM Products
-- GROUP BY clasifica los registros
GROUP BY SupplierID
entonces la función AVG()
usada calculará un promedio independiente para cada uno de los 29 proveedores disponibles:
SupplierID | promedio |
---|---|
1 | 15.67 |
2 | 20.35 |
3 | 31.67 |
... | ... |
28 | 44.5 |
29 | 38.9 |
Filtrado y ordenado
El orden general de operaciones indicado es:
- se filtran los registros de la tabla (
WHERE
); - se agrupan los registros en grupos
GROUP BY
; - se ordena el resultado (
ORDER BY
); - limitar el número de registros de salida (
LIMIT
).
Supóngase que además se necesita filtrar los datos anómalos de la tabla.
En tal caso se usa la cláusula WHERE
,
la cual siempre va antes de GROUP BY
:
SELECT SupplierID, ROUND(AVG(Price),2) as promedio FROM Products
-- WHERE filtra por registros
WHERE SupplierID IS NOT NULL
-- GROUP BY clasifica los registros
GROUP BY SupplierID
-- ORDER BY ordena los resultados de la funcion de agregación
ORDER BY promedio
En este caso se obtienen los precios promedio de los 29 proveedores pero ordenados de menor a mayor:
SupplierID | promedio |
---|---|
10 | 4.5 |
21 | 10.75 |
... | ... |
4 | 46.0 |
18 | 140.75 |
Ejemplo adicional: top 3 de ventas
Supóngase que se desea conocer a los 3 productos más vendidos.
Entonces al agrupado y al ordenamiento se agrega la limitación de resultados con el operador LIMIT
:
-- Lectura de la tabla de ventas
SELECT ProductID, SUM(Quantity) as Ventas FROM OrderDetails
-- WHERE filtra por registros
WHERE ProductID IS NOT NULL
-- Agrupado por producto
GROUP BY ProductID
-- Ordenado de manera descendente - los más vendidos primero
ORDER BY Ventas DESC
-- seleccion de los primeros 3 registros
LIMIT 3
Resultado:
ProductID | Ventas |
---|---|
31 | 458 |
60 | 430 |
35 | 369 |
HAVING
HAVING
habilita filtrar registros en base a operaciones realizadas sobre grupos.
Por este motivo, el HAVING
debe ir siempre después del GROUP BY
.
Por ejemplo, imagínese que se necesita calcular el total de ventas de una lista de productos.
La tabla OrderDetails
registra un total de 518 pedidos,
donde cada pedido consta de un único producto y su cantidad deseada por cada cliente y en cada compra:
-- Total de operaciones de venta registradas
SELECT COUNT(OrderID) FROM OrderDetails
El total de ventas de cada producto se obtiene por agregación:
-- Ventas totales por producto
SELECT ProductID, SUM(Quantity) as Ventas FROM OrderDetails
GROUP BY ProductID
Donde se observa que hay 77 totales de ventas, uno por producto:
ProductID | Ventas |
---|---|
1 | 159 |
2 | 341 |
3 | 80 |
... | ... |
76 | 198 |
77 | 108 |
Si además se necesita mostrar solamente aquellos productos que superen un umbral de ventas se recurre a la cláusula HAVING
, a la cual se le puede agregar un ordenamiento:
-- Productos con ventas por encima de un umbral
SELECT ProductID, SUM(Quantity) as Ventas FROM OrderDetails
GROUP BY ProductID
HAVING Ventas > 350
ORDER BY Ventas
ProductID | Ventas |
---|---|
35 | 369 |
60 | 430 |
31 | 458 |
HAVING
vs WHERE
WHERE
filtra sobre campos,
en tanto que
HAVING
filtra sobre el resultado de las funciones de agregación.
WHERE
WHERE
no permite trabajar con la salida de las funciones de agregación:
Concatenar agregaciones
No se puede concatenar funciones de agregación.
Ejemplo:
Ejemplo:
-- ERROR: concatenado de funciones de agregación
SELECT ProductID, SUM(Quantity) as Ventas FROM OrderDetails
GROUP BY ProductID
HAVING MAX(TOTAL) -- ERROR
ORDER BY TOTAL
Para evitar este problema existen las subconsultas (subqueries).
Orden de cláusulas
El orden general para poder especificar los distintos operadores y cláusulas cuando hay agregación es el siguiente:
-- Orden de operaciones
SELECT ... FROM ....
WHERE ...
GROUP BY ...
HAVING ...
ORDER By ...
LIMIT ...
Nótese de los ejemplos previos que muchas de estas cláusulas son de uso opcional. Sin embargo, sí es necesario respetar el orden de uso de cada una para evitar errores.