FUNCIONES DE AGREGACIÓN Las funciones de agregación son funciones que toman una colección de valores y devuelven como resultado un único valor. El SQL nos ofrece las siguientes funciones de agregación para efectuar varias operaciones sobre los datos de una base de datos: FUNCIÓN DESCRIPCIÓN COUNT Nos da el número total de filas seleccionadas SUM Suma los valores de una columna MIN Nos da el valor mínimo de una columna MAX Nos da el valor máximo de una columna AVG Calcula el valor medio de una columna Los ejemplos que muestran el uso de cada una de las funciones se realizarán con la base de datos EMPRESA que se anexa al final del documento. CONTAR REGISTROS (COUNT) Una pregunta frecuente que deben responder las bases de datos es: “¿qué tan a menudo aparece en la tabla un cierto tipo de dato?” Por ejemplo, se podría querer averiguar la cantidad de empleados que están registrados en la base de datos. Lo anterior se responde utili zando el comando COUNT que cuenta el número de filas en una tabla determinada, en este caso, la tabla empleado. La función COUNT, normalmente se aplica a todas las columnas de la tabla o tablas seleccionadas. Por lo tanto, COUNT(*) contará todas las filas de la tabla o las tablas que cumplan las condiciones. Si se utilizase COUNT(distinct columna), sólo contaría los valores que no fuesen nulos ni repetidos, y si se utilizase COUNT (columna), sólo contaría los valores que no fuesen nulos. Ejemplos: Mostrar cuantos empleados hay registrados en la base de datos. select count(*) as "NUMERO EMPLEADOS" from empleado; +------------------+ | NUMERO EMPLEADOS | +------------------+ | 14 | +------------------+ 1 row in set (0.00 sec) Mostrar el número de cargos registrados en la base de datos. select count(DISTINCT CARGO) as "NUMERO DE CARGOS" from empleado; +------------------+ | NUMERO DE CARGOS | +------------------+ | 5 | +------------------+ 1 row in set (0.00 sec) La cláusula GROUP BY seguida de una lista de atributos permite agrupar las tuplas en grupos que tengan los mismos valores en todos los atributos de esa lista. Por ejemplo: Cuantos empleados hay en cada departamento? Select nombre_dep as DEPARTAMENTO, count(*) as "NUMERO DE EMPLEADOS" from empleado, departamento where cod_dep=deptno group by deptno; +---------------+---------------------+ | DEPARTAMENTO La cláusula GROUP BY nos sirve para agrupar filas según las columnas que indique esta cláusula. | NUMERO DE EMPLEADOS | +---------------+---------------------+ | contabilidad | 3 | | investigacion | 5 | | ventas 6 | | +---------------+---------------------+ 3 rows in set (0.00 sec) Observe el uso de GROUP BY para agrupar todos los registros de cada departamento. Sin dicha cláusula, todo lo que se hubiera obtenido sería un mensaje de error: Select nombre_dep as DEPARTAMENTO, count(*) as "NUMERO DE EMPLEADOS" from empleado, departamento where cod_dep=deptno; ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause Mostrar cuantos empleados hay por cada cargo. select cargo, count(*) as “empleados por cargo” from empleado group by cargo; +------------+---------------------+ | cargo | empleados por cargo | +------------+---------------------+ | ANALISTA | | AUXILIAR | 2 | 3 | | PRESIDENTE | 1 | | SUPERVISOR | 4 | | VENDEDOR 4 | | +------------+---------------------+ 5 rows in set (0.00 sec) SUMAR (SUM) La función SUM retorna la suma de un conjunto de valores. Si el conjunto resultado no tiene registros, SUM() retorna NULL. La palabra clave DISTINCT puede usarse en MySQL 5.0 para sumar sólo los valores distintos del conjunto. Ejemplos: Mostrar la suma de los salarios por departamento select nombre_dep as departamento, sum(salario) deptno; +---------------+--------------+ | departamento | Suma Salario | +---------------+--------------+ | contabilidad | 8750 | | investigacion | 10875 | | ventas | 9400 | +---------------+--------------+ 3 rows in set (0.00 sec) as “Suma Salario” from empleado,departamento where cod_dep=deptno group by Mostrar el código de los departamentos donde la suma de los salarios de sus empleados es mayor a 9000 select deptno from empleado group by deptno having sum(salario) >9000; +--------+ | deptno | La cláusula HAVING especifica condiciones de búsqueda para grupos de filas; lleva a cabo la misma función que antes cumplía la cláusula WHERE para las filas de toda la tabla, pero ahora las condiciones se aplican a los grupos obtenidos. +--------+ | 20 | | 30 | +--------+ 2 rows in set (0.00 sec) El ejemplo anterior pero mostrando el código y nombre de los departamentos donde la suma de los salarios de sus empleados es mayor a 9000. select deptno as CODIGO ,nombre_dep as NOMBRE from empleado,departamento where cod_dep=deptno group by deptno having sum(salario) >9000; +--------+---------------+ | CODIGO | NOMBRE | +--------+---------------+ | 20 | investigacion | | 30 | ventas | +--------+---------------+ 2 rows in set (0.00 sec) VALOR MÁXIMO ( MAX) La función MAX halla el valor más alto de una columna. También aplica la clausula GROUP BY para agrupar registros. Ejemplos: Mostrar el salario más alto. select max(salario) as "salario mas alto" from empleado; +------------------+ | salario mas alto | +------------------+ | 5000 | +------------------+ 1 row in set (0.00 sec) Mostrar el nombre y el salario del empleado que más gana en la empresa. En esta consulta se pide el registro que tiene el valor máximo de determinada columna. En MySQL 5.0 (y en SQL estándar), esto se hace con una subconsulta: Select nombre, salario from empleado where salario = (select max(salario) from empleado); +-------------+---------+ | nombre | salario | +-------------+---------+ | Clara Lopez | 5000 | +-------------+---------+ 1 row in set (0.35 sec) Otra solución es ordenar las columnas por precio, en forma descendente, y obtener solamente el primer registro utilizando la cláusula LIMIT, específica de MySQL: select nombre, salario from empleado order by salario desc limit 1; +-------------+---------+ | nombre | salario | +-------------+---------+ | Clara Lopez | Si se desea que, al hacer una consulta, los datos aparezcan en un orden determinado, es preciso utilizar la cláusula ORDER BY en la sentencia SELECT. 5000 | +-------------+---------+ 1 row in set (0.35 sec) Si hubiese varios empleados que presenten el salario más alto, la solución LIMIT sólo mostraría el primero de ellos. Ejemplo para cuando requiere mostrar los registros de un grupo que tienen el máximo valor en alguna columna: Mostrar el nombre, salario y codigo de departamento del empleado que más gana en cada departamento. Ordene los registros por el campo código de departamento de forma ascendente (de menor a mayor). Select nombre, salario, deptno from empleado as emp1 where salario = (select max(salario) from empleado emp1.deptno=emp2.deptno) order by deptno asc; +-----------------+---------+--------+ | nombre | salario | deptno | +-----------------+---------+--------+ | Clara Lopez | 5000 | 10 | | Alma Scott | 3000 | 20 | | Viviana Morales | 3000 | 20 | | Blake Salas 2850 | 30 | | +-----------------+---------+--------+ 4 rows in set (0.00 sec) VALOR MÍNIMO ( MIN) La función MIN halla el valor más bajo de una columna. También aplica la clausula GROUP BY para agrupar registros. Ejemplos: Mostrar el salario más bajo. select min(salario) as "salario mas bajo" from empleado; +------------------+ | salario mas bajo | +------------------+ | 800 | +------------------+ 1 row in set (0.00 sec) as emp2 where Mostrar el nombre y el salario del empleado que menos gana en la empresa. En esta consulta se pide el registro que tiene el valor máximo de determinada columna. En MySQL 5.0 (y en SQL estándar), esto se hace fácilmente con una subconsulta: Select nombre, salario from empleado where salario = (select min(salario) from empleado); +----------------+---------+ | nombre | salario | Una subconsulta es una consulta incluida dentro de una cláusula WHERE o HAVING de otra consulta. En ocasiones, para expresar ciertas condiciones no hay más remedio que obtener el valor que buscamos como resultado de una consulta. +----------------+---------+ | Carlos Perdomo | 800 | +----------------+---------+ 1 row in set (0.00 sec) Mostrar el nombre, salario y codigo de departamento del empleado que menos gana en cada departamento. Select nombre, salario, deptno from empleado as emp1 where salario = (select min(salario) from empleado as emp2 where emp1.deptno=emp2.deptno) order by deptno asc; +----------------+---------+--------+ | nombre | salario | deptno | +----------------+---------+--------+ | Tito Lopez | 1300 | 10 | | Carlos Perdomo | 800 | 20 | | Ximena Rugeles | 950 | 30 | +----------------+---------+--------+ 3 rows in set (0.00 sec) VALOR PROMEDIO (AVG) La función AVG retorna el valor medio. La opción DISTINCT puede usarse para retornar la media de los valores distintos. Ejemplos: Mostrar el valor promedio de los salarios. select avg(salario) as “promedio Salarios” from empleado; +-------------------+ | promedio Salarios | +-------------------+ | 2073.2143 | +-------------------+ 1 row in set (0.04 sec) Si el ejemplo anterior lo resolvemos usando la palabra DISTINCT, la función AVG calcula el promedio solo con los valores de los salarios que son distintos (descarta valores repetidos). select avg(distinct salario) as "promedio Salarios" from empleado; +-------------------+ | promedio Salarios | +-------------------+ | 2064.5833 | +-------------------+ 1 row in set (0.00 sec) Mostrar el promedio de salario por cada departamento. select deptno, avg(salario) “promedio salario” from empleado group by deptno; +--------+------------------+ | deptno | promedio salario | +--------+------------------+ | 10 | 2916.6667 | | 20 | 2175.0000 | | 30 | 1566.6667 | +--------+------------------+ 3 rows in set (0.00 sec) El ejemplo anterior pero mostrando el nombre del departamento y el valor del promedio sin decimales y con el signo de pesos ($). select nombre_dep departamento, concat("$ ",truncate(avg(salario),0)) "promedio salario" from empleado,departamento where deptno=cod_dep group by deptno; +---------------+------------------+ | departamento | promedio salario | +---------------+------------------+ | contabilidad | $ 2916 | | investigacion | $ 2175 | | ventas | | $ 1566 +---------------+------------------+ 3 rows in set (0.00 sec) Base de datos empresa mysql> select * from empleado; +--------+-----------------+------------+------------+---------+----------+--------+ | codigo | nombre | cargo | f_ingreso | salario | comision | deptno | +--------+-----------------+------------+------------+---------+----------+--------+ | 7369 | Carlos Perdomo | SUPERVISOR | 1980-12-17 | 800 | 50 | 20 | | 7499 | Fernando Velez | VENDEDOR | 1981-02-20 | 1600 | 300 | 30 | | 7521 | Rosario Gomez | VENDEDOR | 1981-12-22 | 1250 | 500 | 30 | | 7566 | Jones Wilson | AUXILIAR | 1981-04-21 | 2975 | 200 | 20 | | 7654 | Martin Vanegas | VENDEDOR | 1998-03-04 | 1250 | 1400 | 30 | | 7698 | Blake Salas | AUXILIAR | 2003-08-04 | 2850 | 150 | 30 | | 7782 | Clark Ken | AUXILIAR | 2006-11-30 | 2450 | 1200 | 10 | | 7788 | Alma Scott | ANALISTA | 2004-07-14 | 3000 | 0 | 20 | | 7839 | Clara Lopez | PRESIDENTE | 1998-11-11 | 5000 | 0 | 10 | | 7844 | Zoila Estrada | VENDEDOR | 2007-10-03 | 1500 | 1300 | 30 | | 7876 | Diego Perez | SUPERVISOR | 1999-11-03 | 1100 | 100 | 20 | | 7900 | Ximena Rugeles | SUPERVISOR | 2000-12-20 | 950 | 2500 | 30 | | 7902 | Viviana Morales | ANALISTA | 2001-11-11 | 3000 | 1800 | 20 | | 7934 | Tito Lopez | SUPERVISOR | 2006-06-05 | 1300 | 0 | 10 | +--------+-----------------+------------+------------+---------+----------+--------+ 14 rows in set (0.00 sec) mysql> select * from departamento; +---------+---------------+-----------+ | cod_dep | nombre_dep | ubicacion | +---------+---------------+-----------+ | 10 | contabilidad | cali | | 20 | investigacion | bogota | | 30 | ventas | manizales | +---------+---------------+-----------+ 3 rows in set (0.00 sec)