Está en la página 1de 34

Consultas SQL

4.1 Introducción

Las consultas, las sentencias SELECT se apoyan sobre dos conceptos matemáticos denominados
Algebra relacional
Cálculo relacional

4.2 La sentencia SELECT

La sentencia SELECT permite extraer datos de las tablas en base a condiciones muy diversas.
La operación más básica que podemos hacer es extraer todo lo que hay en una tabla.
select * from proveedores;
select * from partes;
select * from proyectos;
select * from suministra;

4.3 Condiciones

Muy a menudo no necesitaremos mostrar todos los datos de la tabla, sino solo algunos que se especifi-
carán mediante condiciones.
Si por ejemplo, deseáramos mostrar solo los proveedores cuya ciudad sede está en París haríamos algo
como esto.
select * from proveedores
where ciudad="Paris";

Otra posible consulta sería “mostrar todos los proveedores cuyo estado tiene el codigo 10”
select * from proveedores
where estado=10;

39
Bases de datos, Versión 1.1

Las condiciones pueden ser muy complejas, y se pueden construir utilizando los operadores AND y OR.
Por ejemplo, “mostrar todos los proveedores cuya ciudad es Londres y su estado es 10”.
select * from proveedores
where ciudad="Londres"
and estado=10;

Mostrar las partes cuyo peso es mayor de 15.


select * from partes
where peso>19;

No es obligatorio mostrar todos los campos, se pueden mostrar solamente algunos de ellos indicando su
nombre. Por ejemplo, “mostrar el nombre de proveedor y la ciudad de los proveedores cuyo estado sea
20”.
select nombreprov, ciudad
from proveedores
where estado=20;

¿Qué mostrará la siguiente consulta?


select nombreprov
from proveedores
where estado<=10
and
estado>=20;

La respuesta es que no se muestra nada. La condición está mal escrita ya que no puede haber un número
que sea menor de 10 y a la vez mayor de 20.
Mostrar los nombres de proveedores cuyo estado sea 10 y su ciudad Paris o Londres.
Un primer intento sería este .. code-block:: mysql
select nombreprov from proveedores where estado=10 and (ciudad=”Paris” or ciu-
dad=”Londres”);
Sin embargo, no funciona correctamente. La propia pregunta es ambigua
Una posibilidad es que la pregunta fuera así “Mostrar los nombres de proveedores cuyo estado sea
10 y (su ciudad Paris o Londres).”
La otra posibilidad es que la pregunta fuera así “Mostrar los nombres de proveedores cuyo (estado
sea 10 y su ciudad Paris) o Londres.”
Es importante recordar que cuando en una condición hay tres o más elementos de comparación puede
que sea necesario utilizar paréntesis.
Mostrar las partes rojas o verdes que pesen 17 o más.
Esta pregunta debe aclararse antes de resolverse.
Mostrar las partes siempre que pesen 17 o más y que luego cumplan una de estas dos: tener color
rojo o tener color verde.
“Mostrar las partes (rojas o verdes) que pesen 17 o más.”
Mostrar las partes que siendo verdes pesen 17 o más o si no que simplemente sean rojas.

40 Capítulo 4. Consultas SQL


Bases de datos, Versión 1.1

“Mostrar las partes rojas o (verdes que pesen 17 o más).”


Normalmente, se suele asumir la primera pregunta, que se resuelve así
select * from partes
where peso>=17
and
(color="Rojo" or color="Verde");

select * from partes


where
(color="Rojo" or color="Verde")
and peso>=17;

4.4 Consultas con agregados

Se denomina agregado a alguna función de tipo estadístico aplicada a un subconjunto de los datos de
una tabla.

4.4.1 Recuento

La función COUNT nos dice cuantas filas cumplen una cierta condición. No es obligatorio poner dicha
condición.
select count(*) from partes;

Si deseáramos una condición como por ejemplo “hacer el recuento de partes cuyo color sea Azul”
select count(*) from partes
where color="Azul";

¿Cuantas partes hay que no sean rojas?


select count(*) from partes
where color<>"Rojo";

¿Cuantos proveedores hay cuya ciudad sea Londres?


select count(*)
from proveedores
where ciudad="Londres";

¿Cuantas partes hay que sean rojas y pesen más de 16?


select count(*) from partes
where peso>16
and color="Rojo";

¿Cuantos proyectos hay en Madrid?


select count(*) from proyectos
where ciudad="Madrid";

4.4. Consultas con agregados 41


Bases de datos, Versión 1.1

4.4.2 Promedio

Esta función calcula la media aritmética de las filas que cumplan una cierta condición. Tampoco es
obligatorio poner la condición. La función promedio en SQL es AVG(*)
¿Cual es el peso medio de las partes?
select avg(peso) from partes;

¿Cual es la media de peso de la partes azules?


select avg(peso) from partes
where color="Azul";

4.4.3 Máximos y mínimos

Son operaciones que nos devuelven el valor más grande o más pequeño de entre los que cumplan una
condición.
Estas funciones en SQL son
MAX(campo-numérico)
MIN(campo-numérico)
¿Cual es peso más grande de alguna parte?
select max(peso) from partes;

¿Cual es el peso más pequeño de alguna parte?

4.4.4 Sumas

La operación SUM(campo-numérico) efectúa la suma de ese campo para las filas que cumplan una cierta
condición.
¿Cuantas partes en total ha suministrado el proveedor v1?
select sum(cantidad)
from suministra
where numprov="v1";

¿Cuantas partes ha recibido el proyecto y1?


select sum(cantidad)
from suministra
where numproyecto="y1";

¿Cuantas partes p2 ha suministrado el proveedor v2?


select sum(cantidad)
from suministra
where numparte="p2"
and numprov="v2";

42 Capítulo 4. Consultas SQL


Bases de datos, Versión 1.1

4.4.5 Múltiples agregados

A veces no se hará una sola operación matemática sino muchas. En ese caso es muy importante indicar
a SQL en base a qué debe hacer los resultados, o lo que es lo mismo como agrupar antes de hacer las
operaciones.
En SQL se indicarán los grupos sobre los cuales se va a hacer cada operación mediante la cláusula
GROUP BY (campo). Además, al hacer un “group by” es obligatorio también seleccionar el campo por
el que se hacen los grupos.
La respuesta a una pregunta como:”¿Cual es la media de peso de las partes por color?”
select avg(peso), color
from partes
group by (color);

¿Cual es la media de los pesos en función del nombre de parte?


select avg(peso), nombreparte
from partes
group by (nombreparte);

¿Cuantos proveedores hay en cada ciudad?


select count(*), ciudad
from proveedores
group by (ciudad);

¿Cual es la media de suministros por cada proveedor?


select avg(cantidad), numprov
from suministra
group by (numprov);

¿Cual es la media de pesos de las piezas rojas o verdes?


select avg(peso), color
from partes
where color="Rojo"
or color="Verde"
group by (color);

4.4.6 Condiciones de los agregados

Los agregados pueden llevar sus propias condiciones:


NO VAN CON EL WHERE
Van por separado utilizando HAVING
El HAVING debe ir despues del GROUP BY
“Mostrar cuantos proveedores hay por ciudad, pero solo cuando haya dos o más”
La primera parte de este ejercicio es igual que el anterior. Sacamos cuantos proveedores hay por ciudad
select count(*), ciudad
from proveedores
group by (ciudad);

4.4. Consultas con agregados 43


Bases de datos, Versión 1.1

Si ahora deseamos mostrar solo aquellos cuyo recuento sea mayor o igual que 2 debemos añadir una
cláusula HAVING como esta
select count(*), ciudad
from proveedores
group by (ciudad)
having count(*)>=2;

El WHERE es una condición que se aplica antes de hacer los cálculos. Sin embargo, si una vez hechos
los cálculos no deseamos mostrarlos todos deberemos utilizar el HAVING.
“Mostrar cuantos tornillos hay en total”
Al hacer esta consulta se pueden cometer varios errores, como por ejemplo este, que muestra todas las
partes
select count(*), nombreparte from partes
group by nombreparte;

Esto no es exactamente un error, sino más bien una trampa: se hizo el recuento a mano y se hizo trampa
Error: En este caso se ha confundido el where con el having
select count(*), nombreparte from partes
group by nombreparte having nombreparte="Tornillo";

Pregunta: ¿Podríamos quitar el group by? Respuesta: aunque en este caso sí podríamos no se debe hacer.
Cuando nos pidan una operación matemática por grupos, debemos poner group by
select count(*), nombreparte from partes
where nombreparte="Tornillo"
group by nombreparte

4.5 Consultas multitabla

En ocasiones la información que nos pidan puede que esté dispersa por distintas tablas. SQL ofrece un
mecanismo para “conectar” tablas y así poder hacer las comparaciones que nos pidan.
Por ejemplo, si nos piden el nombre de las partes suministradas en una cantidad >=500 descubriremos
que
El nombreparte está en la tabla partes
La cantidad esta en la tabla suministra
Las tablas partes y suministra tienen un campo en común, el campo numparte
Utilizando una cláusula denominada “inner join” SQL puede establecer las correspondencias correctas
entre dos o más tablas.
Cruce de datos entre las tablas partes y suministra basándonos en que el campo numparte de suministra
debe ser igual que el numparte de suministra
De aqui sacamos solamente los campos que nos piden

44 Capítulo 4. Consultas SQL


Bases de datos, Versión 1.1

4.6 Algunos ejercicios resueltos

1. Deseamos saber los numeros de proveedor que realizan suministros


select numprov from suministra;

2. Deseamos saber los numeros de proveedor que realizan suministros pero sin que se muestren
repetidos
select distinct numprov from suministra;

3. Sumar las cantidades que se han suministrado (¿cuantas piezas se han suministrado?)
select sum(cantidad) from suministra;

4. Se desea ver la suma de las distintas cantidades de partes suministradas


select sum(cantidad),numparte from suministra
group by numparte;

5. Se desea saber las cantidades totales que ha suministrado cada proveedor


select sum(cantidad),numprov from suministra
group by numprov;

6. Cantidades totales suministradas por v1 y v4


select sum(cantidad), numprov from suministra
where numprov=’v1’ or numprov=’v4’
group by (numprov);

7. Mostrar los numeros de parte suministrados en una cantidad total mayor o igual que 1000
select sum(cantidad), numparte
from suministra
group by (numparte)
having sum(cantidad)>=1000;

8. Mostrar la suma de las partes suministradas por v1, v2, o v3 en una cantidad mayor de 550
select sum(cantidad),numparte
from suministra
where numprov=’v1’ or numprov=’v2’ or numprov=’v3’
group by (numparte)
having sum(cantidad)>550;

9. Mostrar cuantos proveedores hay en Londres


select count(*) from proveedores
where ciudad=’Londres’;

10. ¿Cuantas partes rojas hay?


select count(*) from partes
where color="Rojo";

11. ¿Qué colores están repetidos en las partes?

4.6. Algunos ejercicios resueltos 45


Bases de datos, Versión 1.1

select count(*),color from partes


group by color
having count(*)>=2;

4.7 Subconsultas

Al hacer consultas hemos observado que hay cláusulas que permiten establecer condiciones.
Al hacer las condiciones es posible que necesitemos hacer una “subpregunta” y que la sentencia SE-
LECT quede algo así
select ....
from ...
where campo>(select max(cantidad) from suministra)

Supongamos una pregunta como la siguiente: “¿Cuales son los nombres de parte que pesan lo mismo
que la parte más pesada?”
Podemos sacar el peso maximo con esta consulta
select max(peso) from partes;

select nombreparte from partes


where peso>=(select max(peso) from partes);

¿Qué nombres de parte pesan más que la media?


Se saca la media
select avg(peso) from partes;
select *
from partes
where peso>=(select avg(peso) from partes);

Dentro de las subconsultas, aparte de las comparaciones típicas como >, >=, <>, <=, <, etc... existen
otros elementos para hacer comparaciones
EXISTS: nos dará las filas donde exista alguna fila que cumpla la condición
ALL: la condición deben cumplirla todas las filas
12. ¿Qué nombres de parte corresponden a una pieza azul o almacenada en París?
select nombreparte from partes
where color="Azul" or ciudad="Paris"

13. ¿Qué colores tienen las distintas partes que no sean tornillos?
select * from partes
where nombreparte<>"Tornillo";

14. ¿Cuantos proveedores hay que no tengan su almacén en Atenas?


select count(*) from proveedores
where ciudad<>"Atenas";

15. ¿Qué nombres de parte se suministran en una cantidad mayor o igual de 400?

46 Capítulo 4. Consultas SQL


Bases de datos, Versión 1.1

select nombreparte,cantidad
from partes inner join suministra
on partes.numparte=suministra.numparte
where cantidad>=400;

16. ¿Qué proveedores suministran partes en una cantidad <300?


Por un lado, el nombre de proveedor está en la tabla proveedores, que podemos ver haciendo esta con-
sulta
select * from proveedores;

numprov nombreprov estado ciudad


v1 Smith 20 Londres
v2 Jones 10 Paris
v3 Blake 30 Paris
v4 Clarke 20 Londres
v5 Adams 30 Atenas
Sin embargo, las cantidades de suministro están en la tabla suministra que podemos ver ejecutando esta
consulta
select * from suministra;

numprov numparte numproyecto cantidad


v1 p1 y1 200
v1 p1 y4 700
v2 p3 y1 400
v2 p3 y2 200
v2 p3 y3 300
v2 p3 y4 500
v2 p3 y5 600
v2 p3 y6 400
v2 p3 y7 600
v2 p5 y2 100
v3 p3 y1 200
v3 p4 y2 500
v4 p6 y3 300
v4 p6 y7 300
v5 p1 y4 100
v5 p2 y2 200
v5 p2 y4 100
v5 p3 y4 200
v5 p4 y4 800
v5 p5 y4 400
v5 p5 y5 500
v5 p6 y2 200
v5 p6 y4 500
Como la información está dispersada, necesitamos cruzar las tablas con un inner join teniendo en cuenta
que tienen un campo igual, en este caso el campo numprov. Podemos “hacer el cruce” haciendo un inner
join con esta consulta
select * from proveedores inner join suministra
on proveedores.numprov=suministra.numprov;

4.7. Subconsultas 47
Bases de datos, Versión 1.1

Cuyo resultado es que se cruzan los datos correctamente y se obtiene una tabla como esta
numprov numparte numproyecto cantidad numprov nombreprov estado ciudad
v1 p1 y1 200 v1 Smith 20 Londres
v1 p1 y4 700 v1 Smith 20 Londres
v2 p3 y1 400 v2 Jones 10 Paris
v2 p3 y2 200 v2 Jones 10 Paris
v2 p3 y3 300 v2 Jones 10 Paris
v2 p3 y4 500 v2 Jones 10 Paris
v2 p3 y5 600 v2 Jones 10 Paris
v2 p3 y6 400 v2 Jones 10 Paris
v2 p3 y7 600 v2 Jones 10 Paris
v2 p5 y2 100 v2 Jones 10 Paris
v3 p3 y1 200 v3 Blake 30 Paris
v3 p4 y2 500 v3 Blake 30 Paris
v4 p6 y3 300 v4 Clarke 20 Londres
v4 p6 y7 300 v4 Clarke 20 Londres
v5 p1 y4 100 v5 Adams 30 Atenas
v5 p2 y2 200 v5 Adams 30 Atenas
v5 p2 y4 100 v5 Adams 30 Atenas
v5 p3 y4 200 v5 Adams 30 Atenas
v5 p4 y4 800 v5 Adams 30 Atenas
v5 p5 y4 400 v5 Adams 30 Atenas
v5 p5 y5 500 v5 Adams 30 Atenas
v5 p6 y2 200 v5 Adams 30 Atenas
v5 p6 y4 500 v5 Adams 30 Atenas
Si ponemos la condición que nos falta el ejercicio se resuelve correctamente
select nombreprov,cantidad
from proveedores inner join suministra
on proveedores.numprov=suministra.numprov
where cantidad<300
order by nombreprov desc;

17. ¿Cuantos proveedores suministran partes en una cantidad <300?


Para orientarnos, extraemos las filas en
las que la cantidad es menor de 300

select numprov from suministra where cantidad<300;

Si hacemos el recuento, observaremos que hay


9 filas, pero proveedores reales solo están v1, v2, v3 y v5.

select count(numprov)
from suministra
where cantidad<300;

Si ponemos distinct, no nos repetirá los proveedores

select distinct numprov


from suministra
where cantidad<300;

Por tanto la solución pasa por hacer el recuento

48 Capítulo 4. Consultas SQL


Bases de datos, Versión 1.1

de los distintos numprov

select count(distinct numprov)


from suministra
where cantidad<300;

18. ¿Qué nombre tienen las partes suministradas en una cantidad total de 550 o más?
select sum(cantidad), partes.numparte,nombreparte
from suministra
inner join partes
on suministra.numparte=partes.numparte
group by (partes.numparte)
having sum(cantidad)>=550;

19. ¿Qué nombres de parte suministran los distintos proveedores?


select nombreprov, nombreparte
from proveedores inner join suministra
on suministra.numprov=proveedores.numprov
inner join partes
on partes.numparte=suministra.numparte;

20. Queremos saber los proveedores que están ubicados en el mismo sitio que alguna parte.
Examinemos la tabla partes
numparte nombreparte color peso ciudad
p1 Tuerca Rojo 12 Londres
p2 Perno Verde 17 Paris
p3 Tornillo Azul 17 Roma
p4 Tornillo Rojo 14 Londres
p5 Leva Azul 12 Paris
p6 Engranaje Rojo 19 Londres
Examinemos la tabla proveedores
numprov nombreprov estado ciudad
v1 Smith 20 Londres
v2 Jones 10 Paris
v3 Blake 30 Paris
v4 Clarke 20 Londres
v5 Adams 30 Atenas
Se puede comprobar que no nos piden para nada datos de la tabla suministra. Lo único que se necesita
es emparejar las filas donde las ciudades sean iguales.
select nombreprov,nombreparte,partes.ciudad
from partes
inner join proveedores
on partes.ciudad=proveedores.ciudad;

21. ¿Como se llaman las piezas que se suministran en la cantidad máxima?


select nombreparte,max(cantidad) from suministra
inner join partes
on suministra.numparte=partes.numparte
where cantidad=(select max(cantidad) from suministra);

4.7. Subconsultas 49
Bases de datos, Versión 1.1

22. ¿Que numeros de proveedores suministran por encima de la media de suministros?


select numprov, cantidad
from suministra
where cantidad >
(
select avg(cantidad) from suministra
);

Cuidado: si nos dijeran "suministran una cantidad


total que esté por encima de la media", deberíamos
sumar las cantidades por proveedor y compararlas con la media.

select sum(cantidad), numprov


from suministra
group by numprov
having sum(cantidad)>
(
select avg(cantidad) from suministra
);

23. Números de parte suministradas en una cantidad media mayor de 450


select avg(cantidad),numparte
from suministra
group by numparte
having avg(cantidad)>450;

24. ¿Cual es el peso medio de las partes?


select avg(peso) from partes;

25. Obtener el nombre de los provedores, el nombre de parte que suministran y la cantidad en que
suministran
select nombreprov, nombreparte,cantidad
from proveedores
inner join suministra
on
suministra.numprov=proveedores.numprov
inner join partes
on
suministra.numparte=partes.numparte

26. Obtener las parejas de proveedores que NO están en la misma ciudad


select
prov1.numprov, prov1.ciudad,
prov2.numprov, prov2.ciudad
from proveedores as prov1
inner join proveedores as prov2
where prov1.ciudad<>prov2.ciudad;

27. Mostrar suministros donde el proveedor y la parte hayan resultado ser de una ciudad distinta
select suministra.numprov, suministra.numparte,
proveedores.ciudad, partes.ciudad
from suministra
inner join proveedores

50 Capítulo 4. Consultas SQL


Bases de datos, Versión 1.1

on proveedores.numprov=suministra.numprov
inner join partes
on partes.numparte=suministra.numparte
where
proveedores.ciudad<>partes.ciudad;

28. ¿Cuantos proveedores suministran partes rojas o que pesen 12 gramos o más?
Trozo 1: partes rojas
select numparte from partes where color="Rojo"

Trozo 2: partes que pesan 12 o mas


select numparte from partes where peso>12;

Partes que cumplen alguna de las dos cosas


Los proveedores que hacen suministros están en el campo numprov de la tabla suministra
select numprov from suministra;

29. ¿Cuantas piezas se han suministrado de cada ciudad de piezas?


select sum(cantidad),ciudad from partes
inner join suministra
on suministra.numparte=partes.numparte
group by (ciudad);

30. ¿De qué ciudad de proveedor ha salido la cantidad más grande de suministros?.
Esta pregunta podría entenderse de dos formas “Obtener la cantidad más grande suministrada y la ciudad
del proveedor correspondiente”
En primer lugar necesitamos cruzar “proveedores” y suministra

4.7. Subconsultas 51
Bases de datos, Versión 1.1

v1 p1 y1 200 v1 Smith 20 Londres


v1 p1 y4 700 v1 Smith 20 Londres
v2 p3 y1 400 v2 Jones 10 Paris
v2 p3 y2 200 v2 Jones 10 Paris
v2 p3 y3 300 v2 Jones 10 Paris
v2 p3 y4 500 v2 Jones 10 Paris
v2 p3 y5 600 v2 Jones 10 Paris
v2 p3 y6 400 v2 Jones 10 Paris
v2 p3 y7 600 v2 Jones 10 Paris
v2 p5 y2 100 v2 Jones 10 Paris
v3 p3 y1 200 v3 Blake 30 Paris
v3 p4 y2 500 v3 Blake 30 Paris
v4 p6 y3 300 v4 Clarke 20 Londres
v4 p6 y7 300 v4 Clarke 20 Londres
v5 p1 y4 100 v5 Adams 30 Atenas
v5 p2 y2 200 v5 Adams 30 Atenas
v5 p2 y4 100 v5 Adams 30 Atenas
v5 p3 y4 200 v5 Adams 30 Atenas
v5 p4 y4 800 v5 Adams 30 Atenas
v5 p5 y4 400 v5 Adams 30 Atenas
v5 p5 y5 500 v5 Adams 30 Atenas
v5 p6 y2 200 v5 Adams 30 Atenas
v5 p6 y4 500 v5 Adams 30 Atenas
Una primera aproximación sería esta consulta
select max(cantidad),ciudad from
suministra inner join proveedores
on
suministra.numprov=proveedores.numprov;

Sin embargo esto no funciona porque cualquier operación de agregado no involucra a ninguna fila. De
hecho esa consulta nos devuelve un máximo correcto pero no nos devuelve la ciudad asociada, sino la
primera que encuentra.
Hay que encontrar otra forma de expresar esta consulta
select ciudad
from proveedores inner join suministra
on
suministra.numprov=proveedores.numprov
where cantidad=
(
select max(cantidad) from suministra
);

La otra forma de entender la pregunta sería


“Sumar las cantidades por proveedor y decir la ciudad del proveedor con la cantidad máxima”
Una primera aproximación sería esta
select ciudad from
suministra inner join proveedores
on
suministra.numprov=proveedores.numprov
group by (proveedores.numprov)

52 Capítulo 4. Consultas SQL


Bases de datos, Versión 1.1

having sum(cantidad)>=
ALL
(
select sum(cantidad)
from suministra
group by (numprov)
)
;

31. ¿Qué ciudad de parte tiene la mayor media de suministros?


Cruzamos suministra y partes
select * from suministra
inner join partes
on
suministra.numparte=partes.numparte

Por otra lado, sacamos la media por partes de la tabla suministra


select avg(cantidad) from suministra
group by numparte;

Si mezclamos la primera parte con la segunda


select ciudad from suministra
inner join partes
on
suministra.numparte=partes.numparte
group by partes.numparte
having avg(cantidad)>=
ALL
(
select avg(cantidad) from suministra
group by numparte
);

32.Obtener todos los detalles de todos los proyectos


select nombreprov, nombreparte,nombreproyecto,cantidad
from suministra
inner join proyectos
on
suministra.numproyecto=proyectos.numproyecto
inner join partes
on
suministra.numparte=partes.numparte
inner join proveedores
on
suministra.numprov=proveedores.numprov
;

33. Obtener todos los detalles de todos los proyectos ubicados en Londres.
select nombreprov, nombreparte,nombreproyecto,cantidad
from suministra
inner join proyectos
on
suministra.numproyecto=proyectos.numproyecto

4.7. Subconsultas 53
Bases de datos, Versión 1.1

inner join partes


on
suministra.numparte=partes.numparte
inner join proveedores
on
suministra.numprov=proveedores.numprov
where proyectos.ciudad="Londres"
;

34. Obtener los códigos de proveedor que suministran al proyecto Y1.


select numprov from suministra
where numproyecto=’y1’;

35. Obtener los datos de los proyectos que usan partes en cantidades comprendidas entre 300 y 750.
select distinct proyectos.*
from suministra
inner join proyectos
on
suministra.numproyecto=proyectos.numproyecto
where
( cantidad>=300 ) and ( cantidad<=750 )
order by proyectos.numproyecto
;

36. Obtener las combinaciones posibles parte-color


Este ejercicio requiere tener dos copias de la misma tabla. Será necesario utilizar los alias para combi-
nar la tabla partes consigo misma.
select distinct p1.nombreparte, p2.color
from partes as p1
inner join
partes as p2;

37. Obtener los colores de las partes que se han suministrado por V1.
select partes.color from suministra
inner join
partes
on partes.numparte=suministra.numparte
where numprov=’v1’;

38. Obtener la cantidad total de partes P1 usadas por parte de V1.


Datos del proveedor v1

select * from suministra


where numprov=’v1’;

Suma de todas las partes de v1


select sum(cantidad)
from suministra
where
numprov=’v1’
and
numparte=’p1’;

54 Capítulo 4. Consultas SQL


Bases de datos, Versión 1.1

39. Obtener las parejas de nombres de ciudad tales que un proveedor ubicado en la primera ciudad
suministra a algún proyecto ubicado en la segunda ciudad.
select proveedores.ciudad, proyectos.ciudad
from suministra
inner join proveedores
on
suministra.numprov=proveedores.numprov
inner join proyectos
on
suministra.numproyecto=proyectos.numproyecto;

40. Obtener los códigos de parte suministrados a los proyectos ubicados en la misma ciudad del
proveedor.
select suministra.numparte
from suministra
inner join proyectos
on
suministra.numproyecto=proyectos.numproyecto
inner join proveedores
on
suministra.numprov=proveedores.numprov

where
proveedores.ciudad=proyectos.ciudad;

41. Obtener los códigos de proyecto a los que suministra un proveedor que no está en la misma ciudad.
select suministra.numproyecto
from suministra
inner join proveedores
on
proveedores.numprov=suministra.numprov
inner join proyectos
on
proyectos.numproyecto=suministra.numproyecto
where
proyectos.ciudad<>proveedores.ciudad;

42. Obtener las parejas de partes suministradas por el mismo proveedor.


select distinct s1.numparte,s2.numparte
from suministra as s1
inner join suministra as s2
on
s1.numprov=s2.numprov;

43. Obtener los códigos de parte suministrados a cualquier proyecto que esté ubicado en Londres
select numparte from suministra
inner join proyectos
on
suministra.numproyecto=proyectos.numproyecto
where
proyectos.ciudad="Londres";

44. Obtener los códigos de proyecto que usan al menos una parte suministrada por el proveedor V1

4.7. Subconsultas 55
Bases de datos, Versión 1.1

En primer lugar seleccionamos las partes suministradas por v1


select numparte from suministra
where numprov=’v1’;

En segundo lugar queremos saber los proyectos cuyas partes sean alguna de las que hemos extraído
antes.
select numproyecto from suministra
where numparte in
(
select numparte from suministra
where numprov=’v1’

);

45. Obtener los códigos de proveedor que suministran al menos una parte roja.
Seleccionamos las partes cuyo color es rojo
select numparte from partes where color="Rojo";

Ahora, en la tabla suministra sacamos las filas donde la parte sea alguna de las extraídas antes
select numprov from suministra
where numparte in
(
select numparte from partes
where color="Rojo"
);

Una solución distinta


select numprov from suministra
inner join partes
on suministra.numparte=partes.numparte
where partes.color="Rojo";

46. Obtener los códigos de proyecto cuya ciudad es la primera en la lista de ciudades.
Seleccionamos la ciudad más pequeña
select min(ciudad) from proyectos;

select * from proyectos


where ciudad in
(
select min(ciudad) from proyectos
);

Otra forma de hacerlo con inner join’s sería la siguiente


select p1.numproyecto,p1.ciudad from proyectos as p1
inner join proyectos as p2
on
p1.numproyecto=p2.numproyecto
where p1.ciudad=
(
select min(ciudad) from proyectos
);

56 Capítulo 4. Consultas SQL


Bases de datos, Versión 1.1

47. Obtener los códigos de proyecto a los que se suministra la parte P1 en una cantidad promedio
igual o superior a la cantidad más grande que se suministra al proyecto Y1.
Extraemos la cantidad más grande del proyecto “y1”
select max(cantidad) from suministra
where numproyecto="y1";

Al haber una condición para el promedio deberemos poner algo como esto
select numproyecto,avg(cantidad) from suministra
where numparte=’p1’
group by numproyecto
having avg(cantidad)>=
(
select max(cantidad) from suministra
where numproyecto="y1"
);

48. Obtener los códigos de proveedor de los que suministran la parte P1 a algún proyecto en una
cantidad superior a la cantidad promedio de la parte P1 para ese proyecto.
Podemos empezar intentando sacar la media de partes p1 para cada proyecto
select numproyecto, avg(cantidad) from suministra
where numparte=’p1’
group by numproyecto;

Extraemos las filas de la tabla suministra donde la parte sea p1


select numprov from suministra as s1
where numparte=’p1’
and cantidad >
(
select avg(cantidad) from suministra as s2
where numparte=’p1’
and
s2.numproyecto=s1.numproyecto
group by numproyecto
);

49. Obtener los códigos de proyecto a los que ningún proveedor de Londres suministra una parte roja.
Primero averiguamos los proveedores de Londres que suministran partes rojas.
select suministra.numprov
from suministra
inner join partes
on partes.numparte=suministra.numparte
inner join proveedores
on proveedores.numprov=suministra.numprov
where
proveedores.ciudad="Londres"
and
partes.color="Rojo";

Ahora examinamos la tabla suministra y comprobamos que el proveedor no esté en el conjunto devuelto
por la consulta anterior

4.7. Subconsultas 57
Bases de datos, Versión 1.1

select * from suministra


where numprov
not in
(
select suministra.numprov
from suministra
inner join partes
on partes.numparte=suministra.numparte
inner join proveedores
on proveedores.numprov=suministra.numprov
where
proveedores.ciudad="Londres"
and
partes.color="Rojo"
);

50. ¿Hay algún proveedor que suministre la misma parte a TODOS los proyectos?
Para conseguir la solución a este problema se deben utilizar algunas características de los cuantifi-
cadores.
Replanteamos la pregunta
“se desea saber los proveedores donde para todos los proyectos existe una misma parte suministrada”
o más desarrollado
“proveedores (de la tabla suministra) donde para todo proyecto (de la tabla proyectos) existe un sumin-
istro donde el codigo de proveedor es dicho proveedor y la parte es la misma parte que mirábamos en
suministra”
select numprov from suministra as s1
where not exists
(
select numproyecto from proyectos
where numproyecto not in
(
select numproyecto from suministra as s2
where
s1.numparte=s2.numparte
and
s1.numprov=s2.numprov

);

51. Obtener los códigos de proyecto que usan todas las partes suministradas por el proveedor v1
“Obtener los códigos de proyecto donde para toda parte de la tabla suministra existe una parte sumin-
istrada por v1”
Obtener el conjunto de parte suministradas por v1.
select numparte from suministra
where numprov=’v1’;

Las filas de la tabla suministra donde para toda parte de v1 existe alguna fila asociada

58 Capítulo 4. Consultas SQL


Bases de datos, Versión 1.1

select numprov from suministra as s1


where not exists
(
select numparte from suministra as s2
where numprov=’v1’
and not exists
(
select numparte,numproyecto
from suministra as s3
where
s2.numparte=s3.numparte
and s1.numproyecto=s3.numproyecto
)
);

52. (Para nota) Obtener los pares de proveedores V1 y V2 que suministren EXACTAMENTE el mis-
mo conjunto de partes.
La pregunta podría replantearse como
“obtener parejas de proveedores donde para toda parte de un proveedor de la primera tabla existe otro
proveedor distinto tal que la parte es la misma que la parte del primero”.

4.8 Actualización y borrado

Una vez que se han insertado datos, estos no son inmutables. Pueden cambiarse valores de las filas o
incluso pueden borrarse las filas.
Estas operaciones se hacen con las sentencias UPDATE y DELETE.
Para cambiar valores se hace lo siguiente
UPDATE <TABLA> SET <CAMPO>=VALOR WHERE <CONDICION>
Por ejemplo, si quisiéramos hacer que en la tabla partes se cambiara la ciudad Londres por Madrid
haríamos algo como esto
UPDATE partes SET ciudad="Madrid"
WHERE ciudad="Londres";

Poner en la tabla partes el peso a 30 en todas las partes cuyo peso sea mayor que 16;
update partes set peso=30
where peso>16;

Poner a “Amarillo” el color de las partes de Paris


update partes set color="Amarillo"
where ciudad="Paris";

Para borrar datos


DELETE FROM <TABLA> WHERE <CONDICION>
Borrar todas las partes cuyo peso es 12
delete from partes where peso=12;

4.8. Actualización y borrado 59


Bases de datos, Versión 1.1

60 Capítulo 4. Consultas SQL


CAPÍTULO 5

Programación

5.1 Introducción

Los elementos de los lenguajes de programación son muy similares entre sí y el cambio de lenguaje
solamente supone la modificación de ciertos hábitos.
En el entorno de las bases de datos se pueden encontrar programas que actúen mediante dos mecanismos
distintos. Estos dos mecanismos se definen como
Procedimientos almacenados: residen en el propio servidor de bases de datos.
Programas externos: utilizando algún mecanismo los programas externos se comunican con el
servidor para intercambiar datos mediante un lenguaje de programación cualquiera.
Entre los mecanismos de comunicación más utilizados encontramos ODBC (Open DataBases Commu-
nication). Este estándar especifica claramente a servidores y cliente como tienen que dar o pedir datos.
Una versión modificada de ODBC es JDBC que ha modernizado el estándar pero solo sirve para pro-
gramas Java.

5.2 Procedimientos almacenados

5.2.1 Carga de programas

Para cargar código almacenado en un fichero SQL externo se utiliza lo siguiente


\. d:\oscar\t5\prueba1.sql

5.2.2 Variables

Una variable es una posición de memoria con nombre. Normalmente las variables conllevan un tipo que
restringe lo que podemos almacenar en ella.
En MySQL las variables se declaran con la palabra clave DECLARE.
Los tipos utilizables con las variables son los mismos que tiene MySQL.

61
Bases de datos, Versión 1.1

5.2.3 Declaración de procedimientos

Los procedimientos en MySQL actúan igual que las funciones en Java con las diferencias en la sintaxis.
El primer problema que aparece en los procedimientos MySQL viene dado por el hecho de que los
procedimientos a veces interfieren con el delimitador ”;”. Para evitarlo, debemos avisar a MySQL de
que durante un tiempo cambiaremos de delimitador, para ello se usa la siguiente sentencia
Dentro de “código” podrán ir sentencias que terminarán de forma normal, con el punto y coma ”;”
El problema viene dado porque el intérprete de MySQL intenta procesar todo lo que haya hasta llegar
a un punto y coma. Si no cambiásemos el delimitador, se ejecutaría la definición del procedimiento sin
haber encontrado un “end” y todo fallaría.
Ejercicio: crear un procedimiento que acepte una cantidad c y que seleccione todos los suministros cuyo
campo cantidad sea mayor que c
delimiter //

create procedure mayores (cant int)


begin
select * from suministra
where cantidad>cant;
end

//

delimiter ;

Ejercicio: crear un programa que acepte un color co y una ciudad ci y que busque todas las partes cuyo
color sea ese co pasado y la ciudad ese ci pasado. Co y ci son parámetros y NO LLEVAN COMILLAS
delimiter //
create procedure Color_parte
(color_pasado varchar(20),
ciudad_pasada varchar(20) )
begin
select * from partes
where color=color_pasado
and
ciudad=ciudad_pasada;
end
//

delimiter ;

Ejercicio: crear un procedimiento que permita sumar la cantidad de partes suministradas cuyo color sea
el mismo que un cierto color pasado
drop procedure suministradas_color;

delimiter //

create procedure suministradas_color


( color_pasado varchar(20) )

begin
select sum(cantidad)

62 Capítulo 5. Programación
Bases de datos, Versión 1.1

from suministra
inner join partes
on
suministra.numparte=partes.numparte
where color=color_pasado;
end

//

delimiter ;

call suministradas_color("Rojo");
call suministradas_color("Gris");

Ejercicio: crear un procedimiento que reciba dos cosas


Color_pasado
Nombre_prov_pasado
El procedimiento deberá decirnos cuantas partes de ese color suministra ese nombre de proveedor.
Ejercicio: crear un procedimiento que reciba dos cosas
Nombre_parte_pasada
Cantidad_pasada
El procedimiento deberá decirnos cuantas partes con ese nombre han sido suministradas en una cantidad
mayor o igual que la cantidad pasada
drop procedure mayores_que;
delimiter //
create procedure mayores_que(
nombre_parte_pasada varchar(11),
cantidad_pasada int)

begin
select * from suministra inner join partes
on suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and
cantidad>cantidad_pasada;
end

//
delimiter ;

5.3 Sentencias básicas

5.3.1 Decisiones con IF

La sintaxis de un IF es prácticamente igual a la de Java

5.3. Sentencias básicas 63


Bases de datos, Versión 1.1

IF (<comparacion>) THEN
BEGIN
<sentencias>
END
ELSE
BEGIN
END
END IF;

Ejemplo: crear un procedimiento que extraiga las filas de la tabla suministra que cumplan cierta condi-
cion sobre la cantidad. Si el usuario pasa un simbolo “>” el procedimiento nos devuelve las filas mayores
que cierta cantidad. Si no pasa un “<” nos devuelve las filas con una cantidad menor que la pasada
drop procedure selector_v2;

delimiter //

create procedure selector_v2


( operacion char(1), cantidad_pasada int)
begin
if (operacion="<") then
begin
select * from suministra where
cantidad<cantidad_pasada;
end;
else
begin
select * from suministra where
cantidad>cantidad_pasada;
end;
end if;
end;

//
delimiter ;

Ejercicio:crear un procedimiento que dados los parámetros siguientes compruebe cuantas partes con un
cierto nombre tienen una cantidad menor o mayor que una cierta cantidad pasada
nombre_parte_pasado
cantidad_pasada
operacion
drop procedure selector_v3;
delimiter //

create procedure selector_v3


( nombre_parte_pasada varchar(11),
cantidad_pasada int,
operacion varchar(1) )
begin
if (operacion=">") then
begin
select * from suministra inner join
partes on

64 Capítulo 5. Programación
Bases de datos, Versión 1.1

suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and
cantidad>cantidad_pasada;
end;
else
begin
select * from suministra inner join
partes on
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and
cantidad<cantidad_pasada;
end;
end if;
end;

//
delimiter ;

Ejercicio: ampliar el programa anterior para que soporte búsquedas utilizando los comparadores “<”,
“>”, “>=”, “<=”, “=” y “<>”.

5.3.2 5.3.2 Decisiones múltiples con CASE..WHEN

El programa anterior puede resolverse utilizando sentencias if-then-else anidadas, sin embargo es poco
práctico y difícil de ampliar.
La sintaxis de la sentencia case es la siguiente
CASE <variable>
WHEN ">" THEN
BEGIN
END;
WHEN ">=" THEN
BEGIN
END;
WHEN "<" THEN
BEGIN
END;
...
ELSE
BEGIN

END;
END CASE;

Basándonos en esta sintaxis, una posible solución al problema anterior sería esta
drop procedure selector_v4;
delimiter //
create procedure selector_v4
( nombre_parte_pasada varchar(11),
cantidad_pasada int,
operacion varchar(1) )

5.3. Sentencias básicas 65


Bases de datos, Versión 1.1

begin
case operacion
when ">" then
begin
select * from suministra
inner join partes
on
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and cantidad>cantidad_pasada;
end;
when ">=" then
begin
select * from suministra
inner join partes
on
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and cantidad>=cantidad_pasada;
end;
when "<>" then
begin
select * from suministra
inner join partes
on
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and cantidad<>cantidad_pasada;
end;
when "<" then
begin
select * from suministra
inner join partes
on
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and cantidad<cantidad_pasada;
end;
when "<=" then
begin
select * from suministra
inner join partes
on
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and cantidad<=cantidad_pasada;
end;
when "=" then
begin
select * from suministra
inner join partes
on

66 Capítulo 5. Programación
Bases de datos, Versión 1.1

suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and cantidad=cantidad_pasada;
end;
else
begin
select ("Operacion no reconocida");
end;
end case;
end;
//
delimiter ;

Ejercicio: crear un programa que acepte un nombre de parte,luego dos ciudades C1 y C2 y luego un
comparador que puede ser “AND” o “OR”. El programa debe decirnos las partes que pertenecen a las
dos ciudades o a una de ellas.
drop procedure comparador;
delimiter //

create procedure comparador


( nombre_parte_pasada varchar(11),
c1_pasada varchar(15), c2_pasada varchar(15),
operador varchar(3) )
begin

case operador
when "AND" then
begin
select * from partes as p1, partes as p2
where p1.nombreparte=nombre_parte_pasada
and
p2.nombreparte=nombre_parte_pasada
and (p1.ciudad=c1_pasada
and p2.ciudad=c2_pasada);
end;
when "OR" then
begin
select * from partes as p1, partes as p2
where p1.nombreparte=nombre_parte_pasada
and
p2.nombreparte=nombre_parte_pasada
and (p1.ciudad=c1_pasada
or p2.ciudad=c2_pasada);
end;
else
begin
select ("Escriba OR o AND (mayúsculas)");
end;
end case;

end

//

delimiter ;

5.3. Sentencias básicas 67


Bases de datos, Versión 1.1

5.3.3 Bucles con WHILE

Utilizando la sentencia WHILE podemos repetir una tarea que se repita un cierto número de veces por
medio de una variable.
La sintaxis de WHILE es la siguiente
set variable_control=0;
WHILE (<condicion>) DO
...
<sentencias>
..
set variable_control=variable_control+1;
END WHILE;

Ejercicio resuelto: hacer un programa MySQL que imprima los 10 primeros números pares.
drop procedure pares;
delimiter //

create procedure pares()


begin
declare contador int;
set contador=0;
while (contador<=20) do
select (contador);
set contador=contador+2;
end while;
end;

//
delimiter ;

5.3.4 Cursores

Un cursor es un puntero que apunta a la primera fila del resultado de una consulta. Podemos ir ha-
ciendo avanzar el puntero y procesar cada fila por separado. Podemos dejar de procesar filas cuando lo
deseemos, sin que sea obligatorio examinar todos los resultados.
No se puede declarar variables nuevas despues de un cursor. Es decir, esto no es válido
declare un_cursor cursor for...
declare contador int;

Esto sí es válido
declare contador int;
declare un_cursor cursor for...

Un ejemplo de cursor sería el siguiente


DECLARE nombre_cursor CURSOR FOR SELECT * FROM ..... ;

Para empezar a visitar la primera fila se debe hacer lo siguiente.


No debemos olvidar CERRAR el cursor

68 Capítulo 5. Programación
Bases de datos, Versión 1.1

CLOSE nombre_cursor;

Ejercicio: extraer los proveedores que han recibido las 5 cantidades más grandes de suministros.
drop procedure mejores_clientes;
delimiter //

create procedure mejores_clientes()


begin
declare contador int;
declare num_prov_sacado varchar(5);
declare cantidad_sacada int;
declare cur1 cursor for
select numprov, cantidad from suministra
order by cantidad desc;

open cur1;
set contador=0;
while (contador<5) do
fetch cur1 into num_prov_sacado, cantidad_sacada;
select (num_prov_sacado);
select (cantidad_sacada);
set contador=contador+1;
end while;
close cur1;
end;

//
delimiter ;

Ejercicio: hacer un programa que saque las 2 partes de más peso de la tabla partes.
La consulta para este ejercicio sería:
select * from partes order by peso desc;

Y el procedimiento sería
drop procedure mayores_pesos;
delimiter //
create procedure mayores_pesos()
begin
declare contador int;
declare peso_extraido int;
declare ciudad_extraida varchar(15);
declare cur1 cursor for
select ciudad,peso from partes order by peso desc;
open cur1;
set contador=0;
while (contador<2) do
begin
fetch cur1 into ciudad_extraida,
select (ciudad_extraida),(peso_extraido);
set contador=contador+1;
end;
end while;
close cur1;

5.3. Sentencias básicas 69


Bases de datos, Versión 1.1

end;

//
delimiter ;

Ejercicio: sumar las cinco cantidades más bajas de la tabla suministra.


La consulta sería ésta:
select * from suministra order by cantidad;

Y la solución sería
drop procedure suma_filas;
delimiter //
create procedure suma_filas()
begin
declare contador int;
declare suma int;
declare cantidad_extraida int;
declare cur1 cursor for
select cantidad from suministra
order by cantidad asc;
open cur1;
set suma=0;
set contador=0;
while contador<5 do
fetch cur1 into cantidad_extraida;
set suma=suma+cantidad_extraida;
set contador=contador+1;
end while;
close cur1;
select suma;
end;
//
delimiter ;

5.3.5 Parámetros de salida

Si un procedimiento tiene que devolver cosas puede hacerlo utilizando parámetros en la cabecera que
hayan sido etiquetados como “out”.
drop procedure suma_filas;
delimiter //
create procedure suma_filas(out suma_devuelta int)
begin
declare contador int;
declare suma int;
declare cantidad_extraida int;
declare cur1 cursor for
select cantidad from suministra
order by cantidad asc;
open cur1;
set suma=0;
set contador=0;
while contador<5 do
fetch cur1 into cantidad_extraida;

70 Capítulo 5. Programación
Bases de datos, Versión 1.1

set suma=suma+cantidad_extraida;
set contador=contador+1;
end while;
close cur1;
set suma_devuelta=suma;
end;
//
delimiter ;

Ejercicio: realizar un procedimiento que devuelva en una variable la ciudad del proveedor con una
cantidad total (sumar) de suministros mayor.
La consulta sería algo así
select sum(cantidad),suministra.numprov,
ciudad from suministra
inner join proveedores
on suministra.numprov=proveedores.numprov
group by numprov
having sum(cantidad)>=ALL
(
select sum(cantidad)
from suministra
group by numprov
);

El procedimiento sería así:


drop procedure mayor_suministro;
delimiter //

create procedure mayor_suministro


(out ciudad_devuelta varchar(11) )
begin
declare c_devuelta varchar(11);
declare suma int;
declare num_proveedor varchar(2);
declare cur1 cursor for
select sum(cantidad),suministra.numprov,
ciudad from suministra
inner join proveedores
on suministra.numprov=proveedores.numprov
group by numprov
having sum(cantidad)>=ALL
(
select sum(cantidad)
from suministra
group by numprov
);

open cur1;
fetch cur1 into suma, num_proveedor,c_devuelta;
set ciudad_devuelta=c_devuelta;
close cur1;

end;

//

5.3. Sentencias básicas 71


delimiter ;

5.4 Funciones

La sintaxis de una función es la siguiente


delimiter //

create function <nombre> (parametros) returns string


begin
end;

//

delimiter ;

Ejercicio: construir una función que devuelva la suma total de cantidades de la tabla suministra
La consulta sería así:
select sum(cantidad) from suministra;

Y la función
drop function suma_suministra;
delimiter //
create function suma_suministra() returns int
begin
declare suma int;
declare cur1 cursor for
select sum(cantidad) from suministra;

open cur1;
fetch cur1 into suma;
close cur1;

return suma;
end;

//
delimiter ;

set @s=suma_suministra();

103

También podría gustarte