PRCTICA ORACLE)
OBJETIVO
07
(Base
de
Datos
Relacional
Realizacin de Consultas resumen o de agrupacin. Las consultas de resumen (I) En ORACLE y de la mayora de los motores de bases de datos relacionales, podemos definir un tipo de consultas cuyas filas resultantes son un resumen de las filas de la tabla origen, por eso las denominamos consultas de resumen, tambin se conocen como consultas sumarias. Es importante entender que las filas del resultado de una consulta de resumen tienen una naturaleza distinta a las filas de las dems tablas resultantes de consultas, ya que corresponden a varias filas de la tabla orgen. Para simplificar, veamos el caso de una consulta basada en una sola tabla, una fila de una consulta 'no resumen' corresponde a una fila de la tabla origen, contiene datos que se encuentran en una sola fila del origen, mientras que una fila de una consulta de resumen corresponde a un resumen de varias filas de la tabla origen, esta diferencia es lo que va a originar una serie de restricciones que sufren las consultas de resumen y que veremos a lo largo del tema. En el ejemplo que viene a continuacin tienes un ejemplo de consulta normal en la que se visualizan las filas de la tabla oficinas ordenadas por region, en este caso cada fila del resultado se corresponde con una sola fila de la tabla oficinas, mientras que la segunda consulta es una consulta resumen, cada fila del resultado se corresponde con una o varias
Las consultas de resumen introducen dos nuevas clusulas a la sentencia SELECT, la clusula GROUP BY y la clusula HAVING, son clusulas que slo se pueden utilizar en una consulta de resumen, se tienen que escribir entre la clusula WHERE y la clusula ORDER BY y tienen la siguiente sintaxis:
Las detallaremos en la pgina siguiente del tema, primero vamos a introducir otro concepto relacionado con las consultas de resumen, las funciones de columna. Funciones de columna En la lista de seleccin de una consulta de resumen aparecen funciones de columna tambin denominadas funciones de dominio agregadas. Una funcin de columna se aplica a una columna y obtiene un valor que resume el contenido de la columna. Tenemos las siguientes funciones de columna:
El argumento de la funcin indica con qu valores se tiene que operar, por eso expresin suele ser un nombre de columna, columna que contiene los valores a resumir, pero tambin puede ser cualquier expresin vlida que devuelva una lista de valores. La funcin SUM() calcula la suma de los valores indicados en el argumento. Los datos que se suman deben ser de tipo numrico (entero, decimal, coma flotante o monetario...). El resultado ser del mismo tipo aunque puede tener una precisin mayor. Ejemplo: SELECT SUM(ventas) FROM oficinas Obtiene una sola fila con el resultado de sumar todos los valores de la columna ventas de la tabla oficinas. La funcin AVG() calcula el promedio (la media arimtica) de los valores indicados en el argumento, tambin se aplica a datos numricos, y en este caso el tipo de dato del resultado puede cambiar segn las necesidades del sistema para representar el valor del resultado.
ceros
entran
en
la
media
por
lo
que
sale
igual
En este caso los ceros se han sustituido por valores nulos y no entran en el clculo por lo que la media sale igual a6 (10+5+3+6)/4 = 6
Hasta ahora las consultas de resumen que hemos visto utilizan todas las filas de la tabla y producen una nica fila resultado. Se pueden obtener subtotales con la clusula GROUP BY. Una consulta con una clusula GROUP BY se denomina consulta agrupada ya que agrupa los datos de la tabla origen y produce una nica fila resumen por cada grupo formado. Las columnas indicadas en el GROUP BY se llaman columnas de agrupacin. Ejemplo: SELECT SUM(ventas) FROM repventas Obtiene la suma de las ventas de todos los empleados. SELECT SUM(ventas) FROM repventas GROUP BY oficina Se forma un grupo para cada oficina, con las filas de la oficina, y la suma se calcula sobre las filas de cada grupo. El ejemplo anterior obtiene una lista con la suma de las ventas de los empleados de cada oficina. La consulta quedara mejor incluyendo en la lista de seleccin la oficina para saber a qu oficina corresponde la suma de ventas: SELECT oficina,SUM(ventas) FROM repventas GROUP BY oficina Un columna de agrupacin no puede ser de tipo memo u OLE. La columna de agrupacin se puede indicar mediante un nombre de columna o cualquier expresin vlida basada en una columna pero no se pueden utilizar los alias de campo. Ejemplo: SELECT importe/cant , SUM(importe) FROM pedidos GROUP BY importe/cant Est permitido, equivaldra a agrupar las lneas de pedido por precio unitario y sacar de cada precio unitario el importe total vendido.
Ejemplo: SELECT oficina,SUM(ventas) AS ventas_totales FROM repventas GROUP BY oficina En el resultado aparece una fila con el campo oficina sin valor y a continuacin una cantidad en el campo ventas_totales, esta cantidad corresponde a la suma de las ventas de los empleados que no tienen oficina asignada (campo oficina igual a nulo). La clusula HAVING
La clusula HAVING nos permite seleccionar filas de la tabla resultante de una consulta de resumen.
Eliminamos la tabla: drop table libros; Creamos la tabla: create table libros( titulo varchar2(40) not null, autor varchar2(20) default 'Desconocido', editorial varchar(20), precio number(6,2) ); Ingresamos algunos registros: insert insert insert insert insert insert insert into into into into into into into libros libros libros libros libros libros libros values('El aleph','Borges','Emece',15.90); values('Antologa potica',null,'Planeta',null); values('Alicia en el pais de las maravillas','Lewis Carroll',null,19.90); values('Matematica estas ahi','Paenza','Siglo XXI',15); values('Martin Fierro','Jose Hernandez',default,40); values('Aprenda PHP',default,'Nuevo siglo',null); values('Uno','Richard Bach','Planeta',20);
Averiguemos la cantidad de libros usando la funcin "count()": select count(*) from libros; Note que incluye todos los libros aunque tengan valor nulo en algn campo. Contamos los libros de editorial "Planeta": select count(*) from libros where editorial='Planeta'; Existen 2 libros de editorial "Planeta". Contamos los registros que tienen precio (sin tener en cuenta los que tienen valor nulo), usando la funcin "count(precio)": select count(precio) from libros; La consulta nos retorna el valor 5. Contamos los registros que tienen valor diferente de "null" en "editorial": select count(editorial) from libros; La consulta nos retorna el valor 5.
4- Muestre la cantidad de registros empleando la funcin "count(*)" (6 registros) 5- Cuente la cantidad de medicamentos que tienen laboratorio conocido (5 registros) 6- Cuente la cantidad de medicamentos que tienen precio y cantidad, con alias (5 y 4 respectivamente) 7- Cuente la cantidad de remedios con precio conocido, cuyo laboratorio comience con "B" (2 registros) 8- Cuente la cantidad de medicamentos con nmero de lote distinto de "null" (1 registro) 9- Cuente la cantidad de medicamentos con fecha de vencimiento conocida (6 registros)
10
Unidades Tecnolgicas de Santander. Funciones de grupo (count - max - min - sum - avg)
Ingeniera en Telecomunicaciones. Docente: Ingeniero Rogerio Orlando Beltrn Castro.
Hemos visto que Oracle dispone de funciones que nos permiten contar registros, calcular sumas, promedios, obtener valores mximos y mnimos, las funciones de grupo. Las funciones de grupo operan sobre un conjunto de valores (registros) y retornan un solo valor. Ya hemos aprendido una de ellas, "count()", veamos otras. Se pueden usar en una instruccin "select" y combinarlas con la clusula "group by" (la veremos posteriormente). Todas estas funciones retornan "null" si ningn registro cumple con la condicion del "where" (excepto "count" que en tal caso retorna cero). El tipo de dato del campo determina las funciones que se pueden emplear con ellas. Las relaciones entre las funciones de agrupamiento y los tipos de datos es la siguiente: - count: se puede emplear con cualquier tipo de dato. - min y max: con cualquier tipo de dato. - sum y avg: slo en campos de tipo numrico. La funcin "sum()" retorna la suma de los valores que contiene el campo especificado. Si queremos saber la cantidad total de libros que tenemos disponibles para la venta, debemos sumar todos los valores del campo "cantidad": select sum(cantidad) from libros; Para averiguar el valor mximo o mnimo de un campo usamos las funciones "max()" y "min()" respectivamente. Queremos saber cul es el mayor precio de todos los libros: select max(precio) from libros; Entonces, dentro del parntesis de la funcin colocamos el nombre del campo del cul queremos el mximo valor. La funcin "avg()" retorna el valor promedio de los valores del campo especificado. Queremos saber el promedio del precio de los libros referentes a "PHP": select avg(precio) from libros where titulo like '%PHP%'; Ahora podemos entender porque estas funciones se denominan "funciones de grupo", porque operan sobre conjuntos de registros, no con datos individuales. Tratamiento de los valores nulos:
11
Para conocer la cantidad total de libros, sumamos las cantidades de cada uno: select sum(cantidad) from libros; Retorna 880; verifique la suma, sumando los valores de todos los registros del campo "cantidad". Queremos saber cuntos libros tenemos de la editorial "Emece": select sum(cantidad) from libros where editorial='Emece'; retorna 300.
12
Problema Propuesto: Una empresa almacena los datos de sus empleados en una tabla "empleados".
1- Elimine la tabla y crela con la siguiente estructura: drop table empleados; 2- Creamos la tabla: create table empleados( nombre varchar2(30), documento char(8), domicilio varchar2(30), seccion varchar2(20), sueldo number(6,2),
13
3- Ingrese algunos registros: insert into empleados values('Juan Perez','22333444','Colon 123','Gerencia',5000,2,'10/10/1980'); insert into empleados values('Ana Acosta','23444555','Caseros 987','Secretaria',2000,0,'15/08/1998'); insert into empleados values('Lucas Duarte','25666777','Sucre 235','Sistemas',4000,1,null); insert into empleados values('Pamela Gonzalez','26777888','Sarmiento 873','Secretaria',2200,3,null); insert into empleados values('Marcos Juarez','30000111','Rivadavia 801','Contaduria',3000,0,'26/08/2000'); insert into empleados values('Yolanda Perez','35111222','Colon 180','Administracion',3200,1,'25/09/2001'); insert into empleados values('Rodolfo Perez','35555888','Coronel Olmedo 588','Sistemas',4000,3,null); insert into empleados values('Martina Rodriguez','30141414','Sarmiento 234','Administracion',3800,4,'14/12/2000'); insert into empleados values('Andres Costa','28444555',default,'Secretaria',null,null,'08/08/1990'); 4- Muestre la cantidad de empleados usando "count" (9 empleados) 5- Muestre la cantidad de empleados con fecha de ingreso conocida (6 empleados) 6- Muestre la cantidad de empleados con sueldo (8 empleados) 7- Muestre la cantidad de empleados con sueldo de la seccin "Secretaria" (2 empleados) 8- Muestre el sueldo ms alto y el ms bajo colocando un alias (5000 y 2000 respectivamente) 9- Muestre el valor mayor de "cantidadhijos" de los empleados "Perez" (3 hijos) 10- Muestre la fecha de ingreso ms reciente (max) y la ms lejana (min) (25/09/01 y 10/10/80 respectivamente) 11- Muestre el documento menor (22333444) 12- Muestre el promedio de sueldos de todo los empleados (3400. Note que hay un sueldo nulo y no es tenido en cuenta) 13- Muestre el promedio de sueldos de los empleados de la seccin "Secretara" (2100. Note que hay 3 registros de la seccin solicitada, pero como uno de ellos tiene sueldo nulo, no es tenido en cuenta) 14- Muestre el promedio de hijos de todos los empleados de "Sistemas" (retorna 2) 15- Muestre la cantidad de empleados, la cantidad de empleados con domicilio conocido, la suma de los hijos, el promedio de los sueldos y los valores mnimo y mximo del campo "fechaingreso" de todos los empleados. Empleamos todas las funciones de grupo en una sola consulta y nos retorna 9, 8, 14, 3400, 10/10/80 y 25/09/01. 16- Realice la misma consulta anterior pero ahora de los empleados de la seccin "Recursos". Al no existir tal seccin, "count(*)" y "count(domicilio)" retornan 0 (cero) y las dems funciones de grupo retornan "null".
14
Hemos aprendido que las funciones de grupo permiten realizar varios clculos operando con conjuntos de registros. Las funciones de grupo solas producen un valor de resumen para todos los registros de un campo. Podemos generar valores de resumen para un solo campo, combinando las funciones de agregado con la clusula "group by", que agrupa registros para consultas detalladas. Queremos saber la cantidad de libros de cada editorial, podemos tipear la siguiente sentencia: select count(*) from libros where editorial='Planeta'; y repetirla con cada valor de "editorial": select count(*) from libros where editorial='Emece'; select count(*) from libros where editorial='Paidos'; ... Pero hay otra manera, utilizando la clusula "group by": select editorial, count(*) from libros group by editorial; La instruccin anterior solicita que muestre el nombre de la editorial y cuente la cantidad agrupando los registros por el campo "editorial". Como resultado aparecen los nombres de las editoriales y la cantidad de registros para cada valor del campo. Los valores nulos se procesan como otro grupo. Entonces, para saber la cantidad de libros que tenemos de cada editorial, utilizamos la funcin "count()", agregamos "group by" (que agrupa registros) y el campo por el que deseamos que se realice el agrupamiento, tambin colocamos el nombre del campo a recuperar; la sintaxis bsica es la siguiente: select CAMPO, FUNCIONDEAGREGADO from NOMBRETABLA group by CAMPO; Tambin se puede agrupar por ms de un campo, en tal caso, luego del "group by" se listan los campos, separados por comas. Todos los campos que se especifican en la clusula "group by" deben estar en la lista de seleccin. select CAMPO1, CAMPO2, FUNCIONDEAGREGADO from NOMBRETABLA group by CAMPO1,CAMPO2;
15
16
Eliminamos la tabla: drop table libros; Creamos la tabla: create table libros( codigo number(5), titulo varchar2(40), autor varchar2(30) default 'Desconocido', editorial varchar2(15), precio number(5,2), cantidad number(3), primary key(codigo) ); Ingresamos algunos registros: insert insert insert insert insert insert insert insert insert insert into into into into into into into into into into libros libros libros libros libros libros libros libros libros libros values(100,'El aleph','Borges','Planeta',15,null); values(234,'Martin Fierro','Jose Hernandez','Emece',22.20,200); values(354,'Antologia poetica',default,'Planeta',null,150); values(478,'Aprenda PHP','Mario Molina','Emece',18.20,null); values(512,'Cervantes y el quijote','Bioy Casares- J.L. Borges','Paidos',28,100); values(643,'Manual de PHP', default, 'Siglo XXI',31.80,120); values(646,'Harry Potter y la piedra filosofal','J.K. Rowling',default,45.00,90); values(753,'Harry Potter y la camara secreta','J.K. Rowling','Emece',null,100); values(889,'Alicia en el pais de las maravillas','Lewis Carroll','Paidos',22.50,200); values(893,'PHP de la A a la Z',null,null,55.90,0);
Queremos saber la cantidad de libros de cada editorial, utilizando la clusula "group by": select editorial, count(*) from libros group by editorial; Aparece el siguiente resultado: EDITORIAL COUNT(*) -------------------------Paidos 2 2 Planeta 2 Emece 3 Siglo XXI 1 El resultado muestra los nombres de las editoriales y la cantidad de registros para cada valor del campo. Note que los valores nulos se procesan como otro grupo. Obtenemos la cantidad libros con precio no nulo de cada editorial: select editorial, count(precio)
17
18
19
As como la clusula "where" permite seleccionar (o rechazar) registros individuales; la clusula "having" permite seleccionar (o rechazar) un grupo de registros. Si queremos saber la cantidad de libros agrupados por editorial usamos la siguiente instruccin ya aprendida: select editorial, count(*) from libros group by editorial; Si queremos saber la cantidad de libros agrupados por editorial pero considerando slo algunos grupos, por ejemplo, los que devuelvan un valor mayor a 2, usamos la siguiente instruccin: select editorial, count(*) from libros group by editorial having count(*)>2; Se utiliza "having", seguido de la condicin de bsqueda, para seleccionar ciertas filas retornadas por la clusula "group by". Veamos otros ejemplos. Queremos el promedio de los precios agrupados por editorial, pero solamente de aquellos grupos cuyo promedio supere los 25 pesos: select editorial, avg(precio) from libros group by editorial having avg(precio)>25; En algunos casos es posible confundir las clusulas "where" y "having". Queremos contar los registros agrupados por editorial sin tener en cuenta a la editorial "Planeta". Analicemos las siguientes sentencias: select editorial, count(*) from libros where editorial<>'Planeta' group by editorial; select editorial, count(*) from libros group by editorial having editorial<>'Planeta'; Ambas devuelven el mismo resultado, pero son diferentes. La primera, selecciona todos los registros rechazando los de editorial "Planeta" y luego los agrupa para contarlos. La segunda, selecciona todos los registros, los agrupa para contarlos y finalmente rechaza fila con la cuenta correspondiente a la editorial "Planeta". No debemos confundir la clusula "where" con la clusula "having"; la primera establece condiciones para la seleccin de registros de un "select"; la segunda establece condiciones para la seleccin de registros de una salida "group by". Veamos otros ejemplos combinando "where" y "having". Queremos la cantidad de libros, sin considerar los que tienen precio nulo, agrupados por editorial, sin considerar la editorial "Planeta": select editorial, count(*) from libros
20
Aqu, selecciona los registros rechazando los que no cumplan con la condicin dada en "where", luego los agrupa por "editorial" y finalmente rechaza los grupos que no cumplan con la condicin dada en el "having". Se emplea la clusula "having" con funciones de grupo, esto no puede hacerlo la clusula "where". Por ejemplo queremos el promedio de los precios agrupados por editorial, de aquellas editoriales que tienen ms de 2 libros: select editorial, avg(precio) from libros group by editorial having count(*) > 2; En una clusula "having" puede haber varias condiciones. Cuando utilice varias condiciones, tiene que combinarlas con operadores lgicos (and, or, not). Podemos encontrar el mayor valor de los libros agrupados y ordenados por editorial y seleccionar las filas que tengan un valor menor a 100 y mayor a 30: select editorial, max(precio) as mayor from libros group by editorial having min(precio)<100 and min(precio)>30 order by editorial;
Entonces, usamos la clausula "having" para restringir las filas que devuelve una salida "group by". Va siempre despus de la clusula "group by" y antes de la clusula "order by" si la hubiere.
21
Queremos saber la cantidad de libros agrupados por editorial: select editorial, count(*) from libros group by editorial; Nos devuelve: EDITORIAL COUNT(*) -----------------------Paidos 2 2 Planeta 4 Emece 3 Siglo XXI 1 Queremos saber la cantidad de libros agrupados por editorial pero considerando slo algunos grupos, por ejemplo, los que devuelvan un valor mayor a 2, usamos la siguiente instruccin: select editorial, count(*) from libros group by editorial having count(*)>2; La salida es la siguiente: EDITORIAL COUNT(*) ------------------------Planeta 4 Emece 3 Compare esta salida con la de la sentencia anterior. Queremos el promedio de los precios de los libros agrupados por editorial, pero solamente de aquellos grupos cuyo promedio supere los 25 pesos: select editorial, avg(precio) from libros group by editorial having avg(precio)>25; Queremos la cantidad de libros, sin considerar los que tienen precio nulo (where), agrupados por editorial (group by), sin considerar la editorial "Planeta" (having): select editorial, count(*) from libros where precio is not null
22
Necesitamos el promedio de los precios agrupados por editorial, de aquellas editoriales que tienen ms de 2 libros: select editorial, avg(precio) from libros group by editorial having count(*) > 2; Buscamos el mayor valor de los libros agrupados y ordenados por editorial y seleccionamos las filas que tienen un valor menor a 100 y mayor a 30: select editorial, max(precio) as mayor from libros group by editorial having max(precio)<100 and max(precio)>30 order by editorial;
23
Consultas: 1. El promedio de las ventas, iva y descuento por Cliente. 2. Calcular el total del iva por tipo de artculo. 3. Calcular el total de la venta, el costo y la cantidad de los productos por proveedor mostrando su nit y nombre ordenndolo por ventas mayores en forma ascendente y luego por costo total en forma descendente. 4. Calcula el total de venta, iva y cantidad asi como el promedio de cantidad por nombre de clasificacion1, nombre de clasificacion2 y nombre de clasificacion3, ordenndola primero por el nombre de clasificacion1, luego por nombre de clasificacion2 y por ultimo por nombre de clasificacion3. 5. Si aun cliente se le va ha dar por cada 1000 (mil) pesos un punto por cada compra, listar la cdula del cliente, el nombre del cliente, el total de la compras realizadas y la cantidad de puntos ganadas en el mes de enero de 2005, ordenar por puntos en forma descendente y luego por nombre de cliente en forma ascendente. 6. Listar el nit del proveedor, el nombre del proveedor las ventas totales realizadas y el promedio de las misma del primer semestre del ao 2005 7. Quiero sacar un listado del nombre del producto, la cantidad vendida y el total de venta por precio y costo de los productos del proveedor DISTRIBUIDORA GALVIS CASTILLO, donde las ventas sean mayores a 10000 (diez mil) pesos. 8. Quisiera sacar el reporte de las ventas y el valor del iva a pagar agrupados por IVA (16%,10%, etc) del mes de abril de 2006 9. Listar la cedula y nombre del cliente as como su total de compra durante el ao 2006, de aquellos que tuviesen un total de compra mayor a 300000. 10. Listar el nit y nombre del proveedor as como su total de venta durante el ao 2006, de aquellos que tuviesen un total de venta mayor a 500000. 11. Totalizar las compras pagadas a crdito, identificando el nit y el nombre de la empresa, donde el total de los pagos de crdito sean mayores a 100000. 12. Totalizar y contar las ventas realizadas agrupndolas por su forma de pago.
24
Consultas: 1. Totalizar por cliente el valor de la tarifa cobrada y la cantidad de servicios prestados, identificndolos por el nombre, direccin y telfono 2. Totalizar por vehiculo el valor de la tarifa cobrada y la cantidad de servicios prestados y cuyo estado de servicio sea atendidos identificndolos por placa y nombre, direccin y telfono del propietario del vehiculo. Ordenados por Nombre de propietario ascendente y luego por placa en forma descendente. 3. Totalizar el numero de servicios prestado, as como el promedio de tiempo utilizado por cada uno de los conductores de los vehculos, agrupndolos por nombre y cedula del conductor de fecha de recibido el da 3 de mayo de 2005. Ordenndolos por cedula en forma ascendente. 4. Quiero sacar el promedio y valor total de la tarifa pagada, as como el promedio y total de tiempo por da. 5. Quiero identificar el valor del mnimo y mximo valor pagado por tarifa, el nombre del cliente, la placa del vehiculo, el da de ocurrencia y el nombre del conductor. 6. Quiero identificar el valor del mnimo y mximo tiempo, el nombre del cliente, la placa del vehiculo, el da de ocurrencia y el nombre del conductor de los servicios con estado atendidos. 7. Totalizar la cantidad de servicios cancelados, el tiempo promedio gastado y el valor total de las tarifas, agrupadas por nombre y telfono del cliente, as como la placa y el nombre del propietario, Ordenado por nombre del cliente en forma descendente y luego por nombre del propietario en forma ascendente. 8. Cantidad de servicios prestado, total de tarifa, nombre y cedula de los conductor suspendidos. 9. Cantidad de servicios prestado, total de tarifa, placa de los vehculos suspendidos.
25
26