domingo, 13 de mayo de 2012

36 - Selección de un grupo de registros (having)

Así como la cláusula "where" permite seleccionar (o rechazar) registros individuales; la cláusula "having" permite seleccionar (o rechazar) un grupo de registros.

Si queremos saber la cantidad de libros agrupados por editorial usamos la siguiente instrucción ya aprendida:

 select editorial, count(*) from libros
  group by editorial;
 
Si queremos saber la cantidad de libros agrupados por editorial pero considerando sólo algunos grupos, por ejemplo, los que devuelvan un valor mayor a 2, usamos la siguiente instrucción:

 select editorial, count(*) from libros
  group by editorial
  having count(*)>2;
 
Se utiliza "having", seguido de la condición de búsqueda, para seleccionar ciertas filas retornadas por la cláusula "group by".

Veamos otros ejemplos. Queremos el promedio de los precios de los libros agrupados por editorial:

 select editorial, avg(precio) from libros
  group by editorial;
 
Ahora, sólo queremos aquellos 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 cláusulas "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 la cuenta correspondiente a la editorial "Planeta".

No debemos confundir la cláusula "where" con la cláusula "having"; la primera establece condiciones para la selección de registros de un "select"; la segunda establece condiciones para la selección 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
  where precio is not null
  group by editorial
  having editorial<>'Planeta';
 
Aquí, selecciona los registros rechazando los que no cumplan con la condición dada en "where", luego los agrupa por "editorial" y finalmente rechaza los grupos que no cumplan con la condición dada en el "having".
Generalmente se usa la cláusula "having" con funciones de agrupamiento, esto no puede hacerlo la cláusula "where". Por ejemplo queremos el promedio de los precios agrupados por editorial, de aquellas editoriales que tienen más de 2 libros:

 select editorial, avg(precio) from libros
  group by editorial
  having count(*) > 2; 
 
Podemos encontrar el mayor valor de los libros agrupados por editorial y luego seleccionar las filas que tengan un valor mayor o igual a 30:

 select editorial, max(precio) from libros
  group by editorial
  having max(precio)>=30; 
 
Esta misma sentencia puede usarse empleando un "alias", para hacer referencia a la columna de la expresión:

 select editorial, max(precio) as 'mayor' from libros
  group by editorial
  having mayor>=30;
 
Problema Resuelto: 

Trabajamos con la tabla "libros" que registra los datos de una librería.

Eliminamos la tabla, si existe:

drop table if exists libros;

Creamos la tabla:

create table libros( codigo int unsigned auto_increment,
titulo varchar(20) not null,
 autor varchar(30),
editorial varchar(15),
precio decimal(5,2) unsigned,
primary key (codigo) );

Agregamos algunos registros:

insert into libros (titulo,autor,editorial,precio) values('El aleph','Borges','Planeta',15);
insert into libros (titulo,autor,editorial,precio) values('Martin Fierro','Jose Hernandez','Emece',22.20);
insert into libros (titulo,autor,editorial,precio) values('Antologia poetica','Borges','Planeta',40);
insert into libros (titulo,autor,editorial,precio) values('Aprenda PHP','Mario Molina','Emece',18.20);
insert into libros (titulo,autor,editorial,precio) values('Cervantes y el quijote','Borges','Paidos',36.40);
insert into libros (titulo,autor,editorial,precio) values('Manual de PHP', 'J.C. Paez', 'Paidos',30.80);
 insert into libros (titulo,autor,editorial,precio) values('Harry Potter y la piedra filosofal','J.K. Rowling','Paidos',45.00);
insert into libros (titulo,autor,editorial,precio) values('Harry Potter y la camara secreta','J.K. Rowling','Paidos',46.00);
insert into libros (titulo,autor,editorial,precio) values('Alicia en el pais de las maravillas','Lewis Carroll','Paidos',null);

Queremos averiguar la cantidad de libros agrupados por editorial:

select editorial, count(*) from libros group by editorial;

Queremos conocer la cantidad de libros agrupados por editorial pero considerando sólo los que devuelvan un valor mayor a 2, tipeamos:

select editorial, count(*) from libros group by editorial having count(*)>2;

Necesitamos el promedio de los precios de los libros agrupados por editorial:

select editorial, avg(precio) from libros group by editorial;

Ahora, sólo queremos aquellos cuyo promedio supere los 25 pesos:

select editorial, avg(precio) from libros group by editorial having avg(precio)>25;

Queremos contar los registros agrupados por editorial sin tener en cuenta a la editorial "Planeta". Tipeamos y 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';

Note que ambas retornan la misma salida. La primera, selecciona los registros sin considerar los de la editorial "Planeta" y luego los agrupa para contarlos. La segunda, selecciona todos los registros, los agrupa para contarlos y finalmente rechaza la cuenta correspondiente a la editorial "Planeta". Recuerde no confundir las cláusulas "where" y "having"; la primera establece condiciones para la selección de registros individuales, la segunda establece condiciones para la selección de filas de una salida "group by".

Probamos combinar condiciones "where" y "having". Queremos la cantidad de libros, sin tener en cuenta los que tienen precio nulo, agrupados por editorial, rechazando los de editorial "Planeta":

select editorial, count(*) from libros where precio is not null group by editorial having editorial<>'Planeta';

Para obtener el promedio de los precios agrupados por editorial, de aquellas editoriales que tienen más de 2 libros tipeamos:

select editorial, avg(precio) from libros group by editorial having count(*) > 2;

Para encontrar el mayor valor de los libros agrupados por editorial y luego seleccionar las filas que tengan un valor mayor o igual a 30 usamos:

select editorial, max(precio) from libros group by editorial having max(precio)>=30;

Para esta misma sentencia podemos utilizar un "alias" para hacer referencia a la columna de la expresión:

select editorial, max(precio) as 'mayor' from libros group by editorial having mayor>=30;
 
 
 
Problema Propuesto: 

Una empresa tiene registrados sus clientes en una tabla llamada "clientes".

1- Elimine la tabla "clientes", si existe.

2- Créela con la siguiente estructura:
 create table clientes (
  codigo int unsigned auto_increment,
  nombre varchar(30) not null,
  domicilio varchar(30),
  ciudad varchar(20),
  provincia varchar (20),
  telefono varchar(11),
  primary key(codigo)
);

3- Ingrese algunos registros:
 
 insert into clientes (nombre,domicilio,ciudad,provincia,telefono)
  values ('Lopez Marcos', 'Colon 111', 'Córdoba','Cordoba','null');
 insert into clientes (nombre,domicilio,ciudad,provincia,telefono)
  values ('Perez Ana', 'San Martin 222', 'Cruz del Eje','Cordoba','4578585');
 insert into clientes (nombre,domicilio,ciudad,provincia,telefono)
  values ('Garcia Juan', 'Rivadavia 333', 'Villa Maria','Cordoba','4578445');
 insert into clientes (nombre,domicilio,ciudad,provincia,telefono)
  values ('Perez Luis', 'Sarmiento 444', 'Rosario','Santa Fe',null);
 insert into clientes (nombre,domicilio,ciudad,provincia,telefono)
  values ('Pereyra Lucas', 'San Martin 555', 'Cruz del Eje','Cordoba','4253685');
 insert into clientes (nombre,domicilio,ciudad,provincia,telefono)
  values ('Gomez Ines', 'San Martin 666', 'Santa Fe','Santa Fe','0345252525');
 insert into clientes (nombre,domicilio,ciudad,provincia,telefono)
  values ('Torres Fabiola', 'Alem 777', 'Villa del Rosario','Cordoba','4554455');
 insert into clientes (nombre,domicilio,ciudad,provincia,telefono)
  values ('Lopez Carlos', 'Irigoyen 888', 'Cruz del Eje','Cordoba',null);
 insert into clientes (nombre,domicilio,ciudad,provincia,telefono)
  values ('Ramos Betina', 'San Martin 999', 'Cordoba','Cordoba','4223366');
 insert into clientes (nombre,domicilio,ciudad,provincia,telefono)
  values ('Lopez Lucas', 'San Martin 1010', 'Posadas','Misiones','0457858745');

4- Obtenga el total de los registros agrupados por provincia:
 
5- Obtenga el total de los registros agrupados por ciudad y provincia:
 

6- Obtenga el total de los registros agrupados por ciudad y provincia sin considerar los que tienen 
menos de 2 clientes:
 

7- Obtenga el total de los registros sin teléfono nulo, agrupados por ciudad y provincia sin 
considerar los que tienen menos de 2 clientes: 
 
 
 
Otros problemas: 
A) Un comercio que tiene un stand en una feria registra en una tabla llamada 
"visitantes" algunos datos de las personas que visitan o compran en su stand 
para luego enviarle publicidad de sus productos.

1- Elimine la tabla "visitantes", si existe.

2- Créela con la siguiente estructura:
 
 create table visitantes(
  nombre varchar(30),
  edad tinyint unsigned,
  sexo char(1),
  domicilio varchar(30),
  ciudad varchar(20),
  telefono varchar(11),
  montocompra decimal(6,2)
 );

3- Ingrese algunos registros:
 
 insert into visitantes (nombre,edad, sexo,domicilio,ciudad,telefono,montocompra)
  values ('Susana Molina', 28,'f','Colon 123','Cordoba',null,45.50); 
 insert into visitantes (nombre,edad, sexo,domicilio,ciudad,telefono,montocompra)
  values ('Marcela Mercado',36,'f','Avellaneda 345','Cordoba','4545454',0);
 insert into visitantes (nombre,edad, sexo,domicilio,ciudad,telefono,montocompra)
  values ('Alberto Garcia',35,'m','Gral. Paz 123','Alta Gracia','03547123456',25); 
 insert into visitantes (nombre,edad, sexo,domicilio,ciudad,telefono,montocompra)
  values ('Teresa Garcia',33,'f','Gral. Paz 123','Alta Gracia','03547123456',0);
 insert into visitantes (nombre,edad, sexo,domicilio,ciudad,telefono,montocompra)
  values ('Roberto Perez',45,'m','Urquiza 335','Cordoba','4123456',33.20);
 insert into visitantes (nombre,edad, sexo,domicilio,ciudad,telefono,montocompra)
  values ('Marina Torres',22,'f','Colon 222','Villa Dolores','03544112233',25);
 insert into visitantes (nombre,edad, sexo,domicilio,ciudad,telefono,montocompra)
  values ('Julieta Gomez',24,'f','San Martin 333','Alta Gracia','03547121212',53.50);
 insert into visitantes (nombre,edad, sexo,domicilio,ciudad,telefono,montocompra)
  values ('Roxana Lopez',20,'f','Triunvirato 345','Alta Gracia',null,0);
 insert into visitantes (nombre,edad, sexo,domicilio,ciudad,telefono,montocompra)
  values ('Liliana Garcia',50,'f','Paso 999','Cordoba','4588778',48);
 insert into visitantes (nombre,edad, sexo,domicilio,ciudad,telefono,montocompra)
  values ('Juan Torres',43,'m','Sarmiento 876','Cordoba','4988778',15.30);

4- Obtenga el total de las compras agrupados por ciudad y sexo:
 
5- Obtenga el total de las compras agrupados por ciudad y sexo, considerando sólo las sumas 
superiores a 50 pesos:
 
6- Muestre el monto mayor de compra agrupado por ciudad, siempre que el valor supere los 30 pesos, 
considerando sólo los visitantes con telefono no nulo:
 
7- Agrupe por ciudad y muestre para cada grupo (ciudad) el total de visitantes, la suma de sus 
compras y el promedio de compras: 
 
B) En una página web se solicitan los siguientes datos para guardar información 

de sus visitas.

1- Elimine la tabla "visitas", si existe.

2- Créela con la siguiente estructura:
 
 create table visitas (
  numero int unsigned auto_increment,
  nombre varchar(30) not null,
  mail varchar(50),
  pais varchar (20),
  puntaje tinyint unsigned,
  primary key(numero)
);
 
 El puntaje va de 0 a 10.

3- Ingrese algunos registros:
 
 insert into visitas (nombre,mail,pais,puntaje)
  values ('Ana Maria Lopez','AnaMaria@hotmail.com','Argentina',9);
 insert into visitas (nombre,mail,pais,puntaje)
  values ('Gustavo Gonzalez','GustavoGGonzalez@yahoo.com','Chile',8);
 insert into visitas (nombre,mail,pais,puntaje)
  values ('Juancito','JuanJosePerez@hotmail.com','Mexico',5);
 insert into visitas (nombre,mail,pais,puntaje)
  values ('Fabiola Martinez','MartinezFabiolaM@hotmail.com','Chile',9);
 insert into visitas (nombre,mail,pais,puntaje)
  values ('Fabiola Martinez',null,'Peru',8);
 insert into visitas (nombre,mail,pais,puntaje)
  values ('Mariana Torres','MarianitaTorres','Peru',7);

4- Muestre el promedio de los puntajes agrupados por pais, considerando sólo 
aquellos países que tiene más de 1 visita:
 
5- Muestre el promedio de los puntajes agrupados por pais, considerando sólo 

aquellos países cuyo promedio es mayor a 8:
 

C) Una empresa registra los datos de sus empleados en una tabla llamada 

"empleados".

1- Elimine la tabla "empleados" si existe:
 
2- Cree la tabla:
 
 create table empleados(
  documento char(8) not null,
  nombre varchar(30) not null,
  sexo char(1),
  domicilio varchar(30),
  fechaIngreso date,
  fechaNacimiento date,
  sueldoBasico decimal(5,2),
  primary key(documento)
 );

3- Ingrese algunos registros:
 
 insert into empleados (documento,nombre,sexo,domicilio,fechaingreso,fechanacimiento,sueldobasico)
  values ('22333111','Juan Perez','m','Colon 123','1990-02-01','1970-05-10',550);
 insert into empleados (documento,nombre,sexo,domicilio,fechaingreso,fechanacimiento,sueldobasico)
  values ('25444444','Susana Morales','f','Avellaneda 345','1995-04-01','1975-11-06',650);
 insert into empleados (documento,nombre,sexo,domicilio,fechaingreso,fechanacimiento,sueldobasico)
  values ('20111222','Hector Pereyra','m','Caseros 987','1995-04-01','1965-03-25',510);
 insert into empleados (documento,nombre,sexo,domicilio,fechaingreso,fechanacimiento,sueldobasico)
  values ('30000222','Luis LUque','m','Urquiza 456','1980-09-01','1980-03-29',700);
 insert into empleados (documento,nombre,sexo,domicilio,fechaingreso,fechanacimiento,sueldobasico)
  values ('20555444','Maria Laura Torres','f','San Martin 1122','2000-05-15','1965-12-22',700);
 insert into empleados (documento,nombre,sexo,domicilio,fechaingreso,fechanacimiento,sueldobasico)
  values ('30000234','Alberto Soto','m','Peru 232','2003-08-15','1989-10-10',420);
 insert into empleados (documento,nombre,sexo,domicilio,fechaingreso,fechanacimiento,sueldobasico)
  values ('20125478','Ana Gomez','f','Sarmiento 975','2004-06-14','1976-09-21',350);
 insert into empleados (documento,nombre,sexo,domicilio,fechaingreso,fechanacimiento,sueldobasico)
  values ('24154269','Ofelia Garcia','f','Triunvirato 628','2004-09-23','1974-05-12',390);

4- La empresa festeja cada mes los cumpleaños de todos los empleados que cumplen 
ese mes. Queremos saber cuántos empleados cumplen años en los meses de agosto a 
diciembre: 
 
5- Se necesita conocer la cantidad de empleados agrupados por fecha de ingreso 
a la empresa sólo de las fechas posteriores a "1990-02-01":
 
 
 

No hay comentarios:

Publicar un comentario