Sei sulla pagina 1di 53

Ejercicios tema 2.

Las consultas simples


Antes de empezar deberas crear la base de datos datos.mdb con las tablas
descritas en el tema 1 clic aqu para verlas.
Nota: Debes crear una consulta por cada ejercicio, no se pueden escribir varias
sentencias SQL en una misma consulta.
Si quieres puedes guardar cada consulta con un nombre que permita identificarla
por ejemplo: consulta_2_1 siendo 2 el nmero del tema y 1 el nmero del
ejercicio dentro del tema.
Si la consulta contiene errores sintcticos no se podr guardar.
Ahora puedes empezar a redactar las sentencias SQL para obtener lo que se pide
en cada ejercicio.
La lista de seleccin
1 Obtener una lista de todos los productos indicando para cada uno su idfab,
idproducto, descripcin, precio y precio con I.V.A. incluido (es el precio anterior
aumentado en un 16%).
2 De cada pedido queremos saber su nmero de pedido, fab, producto, cantidad,
precio unitario e importe.
3 Listar de cada empleado su nombre, n de das que lleva trabajando en la
empresa y su ao de nacimiento (suponiendo que este ao ya ha cumplido aos).
Ordenacin de filas.
4 Obtener la lista de los clientes agrupados por cdigo de representante
asignado, visualizar todas las columnas de la tabla.
5 Obtener las oficinas ordenadas por orden alfabtico de regin y dentro de cada
regin por ciudad, si hay ms de una oficina en la misma ciudad, aparecer
primero la que tenga el nmero de oficina mayor.
6 Obtener los pedidos ordenados por fecha de pedido.
Seleccin de filas.
7 Listar las cuatro lneas de pedido ms caras (las de mayor importe).

8 Obtener las mismas columnas que en el ejercicio 2 pero sacando unicamente


las 5 lneas de pedido de menor precio unitario.
9 Listar toda la informacin de los pedidos de marzo.
10 Listar los nmeros de los empleados que tienen una oficina asignada.
11 Listar los nmeros de las oficinas que no tienen director.
12 Listar los datos de las oficinas de las regiones del norte y del este (tienen que
aparecer primero las del norte y despus las del este).
13 Listar los empleados de nombre Julia.
14 Listar los productos cuyo idproducto acabe en x.

Solucin ejercicios tema 2. Las consultas simples


Ejercicio 1
SELECT idfab,idproducto,descripcion,precio, (precio * 1.16) AS iva_incluido
FROM productos
Los parntesis son opcionales, tambin se puede poner como frmula de clculo:
precio + precio * 16 /100.
Ejercicio 2
SELECT numpedido, fab, producto, cant, importe / cant AS precio_unitario,
importe
FROM pedidos
Ejercicio 3
SELECT nombre, date() - contrato AS dias_trabajados, year(date()) - edad AS
ao_nacimiento
FROM empleados
Aqu hemos utilizado la funcin date() que devuelve el da actual y hemos
utilizado la diferencia de fechas para saber cuntos das han transcurrido entre
las dos fechas. Para saber el ao de nacimiento restamos al ao actual la edad
del empleado. Para obtener el ao actual aplicamos la funcin year() (que
devuelve el ao de una fecha) sobre la fecha actual (date())
Ejercicio 4

SELECT *
FROM clientes
ORDER BY repclie
Ejercicio 5
SELECT *
FROM oficinas
ORDER BY region, ciudad, oficina DESC
Ejercicio 6
SELECT *
FROM pedidos
ORDER BY fechapedido
Ejercicio 7
SELECT TOP 4 *
FROM pedidos
ORDER importe DESC
Para obtener las ms caras tenemos que ordenar por importe y en orden
descendente para que aparezcan las ms caras primero. Adems como slo
queremos las cuatro primeras utilizamos la clusula TOP 4.
Ejercicio 8
SELECT TOP 5 numpedido, fab, producto, cant, importe / cant AS
precio_unitario, importe
FROM pedidos
ORDER BY 5
Ordenamos los pedidos por precio unitario utilizando el n de columna, el precio
unitario es la quinta columna dentro de la lista de seleccin. En este caso la
ordenacin debe ser ascendente.
Ejercicio 9
SELECT *
FROM pedidos
WHERE MONTH(fechapedido) = 3
MONTH(fecha) devuelve el nmero de mes de la fecha.
Ejercicio 10

SELECT numemp
FROM empleados
WHERE oficina IS NOT NULL
Los empleados que tienen asignada una oficina son los que tienen un valor en el
campo oficina.
Ejercicio 11
SELECT oficina
FROM oficinas
WHERE dir IS NULL
El campo dir es el que nos dice quien es el director de la oficina.
Ejercicio 12
SELECT *
FROM oficinas
WHERE region IN ('norte','este')
ORDER BY region DESC
Los valores se ponen entre comillas simples o dobles ya que son valores
alfanumricos. Tambin se puede poner WHERE region = 'norte' OR region = 'este'.
Ordenamos desc para que primero aparezcan las del norte.
Ejercicio 13
SELECT *
FROM empleados
WHERE nombre LIKE 'Julia *'
Los empleados cuyo nombre empiece por Julia, observar que antes del * hay un
espacio en blanco para forzar a que el siguiente carcter despus de la a sea un
blanco y no coja por ejemplo Julian.
Ejercicio 14
SELECT *
FROM productos
WHERE idproducto LIKE '*x'
Ejercicios tema 3. Las consultas multitabla
1 Listar las oficinas del este indicando para cada una de ellas su nmero, ciudad,
nmeros y nombres de sus empleados. Hacer una versin en la que aparecen slo

las que tienen empleados, y hacer otra en las que aparezcan las oficinas del este
que no tienen empleados.
2 Listar los pedidos mostrando su nmero, importe, nombre del cliente, y el
lmite de crdito del cliente correspondiente (todos los pedidos tienen cliente y
representante).
3 Listar los datos de cada uno de los empleados, la ciudad y regin en donde
trabaja.
4 Listar las oficinas con objetivo superior a 600.000 pts indicando para cada una
de ellas el nombre de su director.
5 Listar los pedidos superiores a 25.000 pts, incluyendo el nombre del empleado
que tom el pedido y el nombre del cliente que lo solicit.
6 Hallar los empleados que realizaron su primer pedido el mismo da en que
fueron contratados.
7 Listar los empleados con una cuota superior a la de su jefe; para cada
empleado sacar sus datos y el nmero, nombre y cuota de su jefe.
8 Listar los cdigos de los empleados que tienen una lnea de pedido superior a
10.000 ptas o que tengan una cuota inferior a 10.000 pts.

Solucin ejercicios tema 3. Las consultas multitabla


Ejercicio 1
SELECT oficinas.oficina, ciudad, numemp, nombre
FROM oficinas INNER JOIN empleados ON oficinas.oficina = empleados.oficina
WHERE region = 'este'

Como la columna de emparejamiento oficinas.oficina es clave principal en la


tabla oficinas, es mejor utilizar el JOIN que un producto cartesiano.
Emparejamos las dos tablas por el campo oficina. Las oficinas que no tengan
empleados no salen (es un INNER).
Como queremos slo las oficinas del este aadimos la clusula WHERE con la
condicion. El valor este debe ir entre comillas (es un valor alfanumrico).
Observar que en la lista de seleccin la columna oficina est cualificada (su
nombre est precedido del nombre de la tabla), es necesario cualificarla porque
en las dos tablas existe una columna llamada oficina y el sistema no sabra cul
de las dos escoger.

SELECT oficinas.oficina, ciudad, numemp, nombre


FROM oficinas LEFT JOIN empleados ON oficinas.oficina = empleados.oficina
WHERE region = 'este'

Si queremos que tambin aparezcan las oficinas que no tienen empleados


cambiamos INNER por LEFT (queremos todas las oficinas y la tabla oficinas est a
la izquierda de la palabra JOIN).
Ojo, si en la lista de seleccin ponemos empleados.oficina en vez de
oficinas.oficina, en las filas de oficinas que no tienen empleados el nmero de
oficina aparece nulo.
SELECT oficinas.oficina, ciudad, numemp, nombre
FROM empleados RIGHT JOIN oficinas ON oficinas.oficina = empleados.oficina
WHERE region = 'este'

Esta SELECT es equivalente a la anterior pero hemos cambiado LEFT por RIGHT
porque ahora la tabla oficinas est a la derecha de la palabra JOIN.
Ejercicio 2
SELECT numpedido, importe, clientes.nombre AS cliente, limitecredito
FROM pedidos INNER JOIN clientes ON pedidos.clie = clientes.numclie

En este ejercicio no pueden haber pedidos sin cliente, y lo que nos interesa son
los pedidos, luego tampoco tienen que aparecer los clientes que no tienen
pedidos, por lo tanto utilizamos un INNER JOIN.
Ejercicio 3
SELECT empleados.*, ciudad, region
FROM empleados LEFT JOIN oficinas ON empleados.oficina = oficinas.oficina

Aqu hemos utilizado LEFT JOIN para que tambin salgan los empleados que no
tienen oficina asignada.
Como queremos todos los datos del empleado utilizamos empleados.* para
acortar.
Ejercicio 4
SELECT oficinas.*, nombre AS director
FROM empleados RIGHT JOIN oficinas ON empleados.oficina = oficinas.oficina
WHERE objetivo > 600000

Nos interesan las oficinas con objetivo superior a 600.000pts. luego nos tenemos
que asegurar que salgan todas incluso si no tienen director asignado por eso
utilizamos RIGHT JOIN.
En los valores numricos no utilizar el punto para separar los miles (lo
considerara coma decimal y entendera 600 en vez de 600000).
Ejercicio 5

SELECT numpedido, importe, empleados.nombre AS representante, clientes.nombre AS


cliente
FROM (pedidos INNER JOIN clientes ON pedidos.clie = clientes.numclie) INNER JOIN
empleados ON pedidos.rep = empleados.numemp
WHERE importe > 25000

En este ejercicio no pueden haber pedidos sin representante ni cliente, y lo que


nos interesa son los pedidos, luego tampoco tienen que aparecer los
representantes que no tienen pedidos ni los clientes que no tienen pedidos, por
lo tanto utilizamos un INNER JOIN.
Primero aadimos a cada lnea de pedido los datos del cliente corespondiente
(con el primer INNER) y a cada fila resultante aadimos los datos del
representante correspondiente.
Nota: el representante que nos interesa es el que ha realizado el pedido y ese
dato lo tenemos en el campo rep de pedidos por eso la condicin de
emparejamiento es pedidos.rep = empleados.rep.
Si hubiesemos querido el nombre del representante asignado al cliente, la
condicin hubiera sido clientes.repclie = empleados.numemp.
Ejercicio 6
SELECT empleados.*
FROM empleados INNER JOIN pedidos ON pedidos.rep = empleados.numemp
WHERE fechapedido = contrato

Los representantes que buscamos tienen un pedido con la misma fecha que la de
su contrato, tenemos que aadir a los pedidos los datos del representante
correspondiente para poder comparar los dos campos.
Ejercicio 7
SELECT empleados.*, jefes.numemp AS num_jefe, jefes.nombre AS nombre_jefe, jefes.cuota
AS cuota_jefe
FROM empleados INNER JOIN empleados jefes ON empleados.jefe = jefes.numemp
WHERE empleados.cuota > jefes.cuota

En una misma lnea necesito los datos del empleado y los datos de su jefe, luego
tengo que combinar empleados con empleados. No interesan los empleados que
no tienen jefe luego utilizo INNER. El alias de tabla es obligatorio ya que combino
empleados con la misma.
Ejercicio 8

SELECT numemp
FROM empleados LEFT JOIN pedidos ON pedidos.rep = empleados.numemp
WHERE importe > 10000 OR cuota < 10000

Una posible solucin es combinar pedidos con empleados para poder seleccionar
las lneas de importe > 10000 o cuota < 10000. Hay que utilizar LEFT para que
puedan aparecer empleados con cuota < 10000 que no tengan pedidos.
SELECT rep
FROM pedidos
WHERE importe > 10000
UNION
SELECT numemp
FROM empleados
WHERE cuota < 10000

Esta es otra solucin, obtener por una parte los cdigos de los empleados con una
lnea de pedido > 10000, por otra parte los cdigos de los empleados con cuota <
10000 y finalmente unir las dos listas con una UNION.
Ejercicios tema 4. Las consultas de resumen
1 Cul es la cuota media y las ventas medias de todos los empleados?
2 Hallar el importe medio de pedidos, el importe total de pedidos y el precio
medio de venta (el precio de venta es el precio unitario en cada pedido).
3 Hallar el precio medio de los productos del fabricante ACI.
4 Cul es el importe total de los pedidos realizados por el empleado Vicente
Pantalla?
5 Hallar en qu fecha se realiz el primer pedido (suponiendo que en la tabla de
pedidos tenemos todos los pedidos realizados hasta la fecha).
6 Hallar cuntos pedidos hay de ms de 25000 ptas.
7 Listar cuntos empleados estn asignados a cada oficina, indicar el nmero de
oficina y cuntos hay asignados.
8 Para cada empleado, obtener su nmero, nombre, e importe vendido por ese
empleado a cada cliente indicando el nmero de cliente.
9 Para cada empleado cuyos pedidos suman ms de 30.000 ptas, hallar su
importe medio de pedidos. En el resultado indicar el nmero de empleado y su
importe medio de pedidos.

10 Listar de cada producto, su descripcin, precio y cantidad total pedida,


incluyendo slo los productos cuya cantidad total pedida sea superior al 75% del
stock; y ordenado por cantidad total pedida.
11 Saber cuntas oficinas tienen empleados con ventas superiores a su cuota, no
queremos saber cuales sino cuntas hay.
Solucin ejercicios tema 4. Las consultas de resumen
Ejercicio 1
SELECT AVG(cuota) AS cuota_media, AVG(ventas) AS ventas_media
FROM empleados

Sale una nica fila con el resultado deseado. Siempre que se utilicen expresiones
o funciones en la lista de seleccin, queda mejor utilizar un alias de columna
para que ese aparezca en el encabezado del resultado.
Ejercicio 2
SELECT AVG(importe) AS importe_medio, SUM(importe) AS importe_total, AVG(importe/cant)
AS precio_venta_medio
FROM pedidos

El precio medio de venta es la media aritmtica de los precios unitarios de cada


pedido. El precio unitario se calcula dividiendo el importe del pedido por la
cantidad del pedido: importe/cant, por lo que ponemos AVG(importe/cant).
Ejercicio 3
SELECT AVG(precio) AS p_medio_ACI
FROM productos
WHERE idfab = 'ACI'

Ahora no nos interesan todos los productos sino unicamente los del fabricante
ACI, por lo que aadimos la clusula WHERE para que antes de calcular la media,
elimine del origen de datos los registros que no cumplan la condicin.
Ejercicio 4
SELECT SUM(importe) AS total_pedidos_V_Pantalla
FROM empleados INNER JOIN pedidos ON empleados.numemp = pedidos.rep
WHERE nombre = 'Vicente Pantalla'

El importe total lo tenemos que sacar de la tabla de pedidos, y adems slo nos
interesan los de Vicente Pantalla. Como nos dan el nombre del representante en
vez de su nmero y en el pedido slo tenemos el nmero de representante
tenemos que aadir a las lneas de cada pedido, los datos del representante
correspondiente, por lo que el origen de datos debe ser el que aparece en la
FROM.

Ejercicio 5
SELECT MIN(fechapedido) AS primer_pedido
FROM pedidos

La fecha del primer pedido es la fecha ms antigua de la tabla de pedidos.


Ejercicio 6
SELECT COUNT(*) AS cuantos_pedidos_mayores
FROM pedidos
WHERE importe > 25000

Se poda haber utilizado tambin COUNT(numpedido) o cualquier nombre de


columna que no pueda contener valores nulos, pero COUNT(*) es mejor por ser
ms rpido (la diferencia se nota con tablas muy voluminosas).
Ejercicio 7
SELECT oficina, COUNT(*) AS cuantos_empleados
FROM empleados
GROUP BY oficina

Con esta solucin obtenemos el listado pedido pero no aparecen las oficinas que
no tienen empleados asignados ya que sacamos la informacin de la tabla
empleados y aparece una fila con valor nulo en oficina que contiene el nmero
de empleados que no tienen oficina. Si quisieramos listar incluso las que no
tengan empleados habra que recurrir a la solucin 2
Solucin 2
SELECT oficinas.oficina, COUNT(numemp) AS cuantos_empleados
FROM empleados RIGHT JOIN oficinas ON empleados.oficina = oficinas.oficina
GROUP BY oficinas.oficina

Utilizamos un RIGHT JOIN para que el origen de datos incluya tambin una fila
por cada oficina que no tenga empleados.
En el GROUP BY y en la lista de seleccin hay que indicar el campo oficina de la
tabla oficinas, si ponemos el de la tabla empleados, agrupar todas las oficinas
que no tienen empleados en una fila (la columna empleados.oficina contiene
valor nulo para esas filas).
Aqu no podemos utilizar COUNT(*) por que las oficinas sin empleados
apareceran con 1 en la columna cuantos_empleados ya que para esa oficina hay
una fila.
Ejercicio 8
SELECT numemp, nombre, clie AS cliente, SUM(importe) AS total_vendido
FROM empleados INNER JOIN pedidos ON pedidos.rep = empleados.numemp
GROUP BY numemp, nombre, clie

Necesitamos la tabla de pedidos para el importe vendido a qu cliente,


necesitamos la tabla empleados para el nombre del representante, la de clientes
no la necesitamos ya que nos piden el nmero de cliente y este est en pedidos.
La agrupacin bsica que debemos realizar es por numemp y despus por clie,
pero como aparece el nombre del empleado en la lista de seleccin, hay que
incluirlo tambin en el GROUP BY.
Despus de determinar la agrupacin bsica que nos hace falta, siempre que se
incluye una columna adicional en el GROUP BY hay que comprobar que esa nueva
columna no cambia la agrupacin bsica.
Por ejemplo no podramos aadir al GROUP BY la columna fechapedido ya que se
formaran ms grupos.
Solucin 2
SELECT numemp, nombre, clie AS cliente, SUM(importe) AS total_vendido
FROM empleados LEFT JOIN pedidos ON pedidos.rep = empleados.numemp
GROUP BY numemp, nombre, clie

Si queremos que salgan todos los empleados incluso los que no aparezcan en los
pedidos habra que sustituir el INNER por un LEFT.
Ejercicio 9
SELECT rep, AVG(importe) AS importe_medio
FROM pedidos
GROUP BY rep
HAVING SUM(importe) > 30000

No queremos todos los empleados, unicamente los que tengan un importe total
pedido superior a 30.000, luego tenemos que poner la condicin SUM(importe) >
30000. Como esta condicin contiene una funcin de columna (SUM()) se tiene
que poner en la clusula HAVING ya que selecciona filas de la tabla resultante no
del origen de datos.
Ejercicio 10
SELECT descripcion, precio, SUM(importe) AS total_pedido
FROM productos INNER JOIN pedidos ON pedidos.fab = productos.idfab AND pedidos.producto
= productos.idproducto
GROUP BY idfab, idproducto, descripcion, precio, existencias
HAVING SUM(importe) > existencias * 0.75
ORDER BY 3

La agrupacin bsica es por idfab e idproducto ya que son los dos campos que
conjuntamente identifican un producto.
Como descripcin y precio aparecen en la lista de seleccin y no modifican la
agrupacin bsica los incluimos en el GROUP BY.

Como existencias aparece en el HAVING y no modifica la agrupacin bsica lo


incluimos tambin el el GROUP BY.
Para calcular el 75% de las existencias multiplicamos existencias por 0,75;
observar que en la sentencia SQL hay que utilizar el punto para indicar los
decimales.
Para indicar la columna de ordenacin no podemos utilizar el alias campo,
utilizamos el nmero de orden de la columna dentro de la lista de seleccin. En
este caso la suma de importes es la tercera columna.
Ejercicio 11
Consulta: distintas_oficinas
SELECT DISTINCT oficina
FROM empleados
WHERE ventas > cuota
Consulta: sumaria11
SELECT COUNT(*) AS cuantas_oficinas
FROM distintas_oficinas

Si contamos las oficinas directamente de la tabla empleados nos salen 9 oficinas


ya que la funcin COUNT(nb columna) cuenta los valores no nulos pero los
valores repetidos los cuenta tantas veces como se repiten, como tenemos
oficinas de se repiten en la columna oficina de la tabla oficinas, esas oficinas son
contadas varias veces, hay que contar los valores distintos.
En otros SQL la funcin COUNT puede llevar delante del nombre de la columna la
clusula DISTINCT que indica que slo se tienen que tener en cuenta valores
distintos (no cuenta los repetidos), por ejemplo COUNT(DISTINCT oficina), es una
opcin muy til que desgraciadamente no incluye el SQL de Microsoft JET. Para
solucionar el problema se resuelve con dos consultas, una con la cual nos
quedamos con los valores distintos (en la solucin la consulta se llama
distintas_oficinas), y la otra que nos cuenta esos valores.
Ejercicios tema 5. Las subconsultas
Los ejercicios que te proponemos a continuacin se pueden resolver de varias
maneras, intenta resolverlos utilizando subconsultas ya que de eso trata el tema,
adems un mismo ejercicio lo puedes intentar resolver de diferentes maneras
utilizandos distintos tipos de condiciones, as un ejercicio se puede convertir en
dos o tres ejercicios.
1 Listar los nombres de los clientes que tienen asignado el representante Alvaro
Jaumes (suponiendo que no pueden haber representantes con el mismo nombre).
2 Listar los vendedores (numemp, nombre, y n de oficina) que trabajan en
oficinas "buenas" (las que tienen ventas superiores a su objetivo).

3 Listar los vendedores que no trabajan en oficinas dirigidas por el empleado


108.
4 Listar los productos (idfab, idproducto y descripcin) para los cuales no se ha
recibido ningn pedido de 25000 o ms.
5 Listar los clientes asignados a Ana Bustamante que no han remitido un pedido
superior a 3000 pts.
6 Listar las oficinas en donde haya un vendedor cuyas ventas representen ms
del 55% del objetivo de su oficina.
7 Listar las oficinas en donde todos los vendedores tienen ventas que superan al
50% del objetivo de la oficina.
8 Listar las oficinas que tengan un objetivo mayor que la suma de las cuotas de
sus vendedores.
Solucin ejercicios tema 5. Las subconsultas
Ejercicio 1
SELECT nombre
FROM clientes
WHERE repclie = (SELECT numemp FROM empleados WHERE nombre = 'Alvaro Jaumes' );

Hemos supuesto que no pueden haber dos empleados con el mismo nombre, de lo
contrario habra que aadir ANY antes de la subconsulta.
Ejercicio 2
Solucin 1
SELECT numemp, nombre, oficina
FROM empleados
WHERE oficina IN ( SELECT oficina FROM oficinas WHERE ventas > objetivo );

Con esta solucin buscamos que la oficina del empleado est en la lista de
oficinas que tienen ventas superiores a su objetivo.

Solucin 2
SELECT numemp, nombre, oficina
FROM empleados
WHERE EXISTS ( SELECT * FROM oficinas WHERE empleados.oficina = oficinas.oficina AND
ventas > objetivo );

Con esta solucin buscamos que exista una oficina igual al del empleado y que
tenga ventas superiores a su objetivo. El resultado ser el mismo que con la
solucin 1.

Solucin 3
SELECT numemp, nombre, oficina
FROM empleados
WHERE oficina = ANY ( SELECT oficina FROM oficinas WHERE ventas > objetivo );

Con esta otra comparamos la oficina del empleado con cada una de las oficinas
que tengan ventas superiores a su objetivo, si la oficina del empleado es igual a
alguna de esas oficinas aparece el empleado en el resultado. El resultado ser el
mismo que con la solucin 1.
Ejercicio 3
Solucin 1
SELECT numemp, nombre, oficina
FROM empleados
WHERE NOT EXISTS ( SELECT * FROM oficinas WHERE empleados.oficina = oficinas.oficina AND
dir = 108);

Obtenemos los empleados tales que no exista una oficina igual a la suya que
adems est dirigida por el empleado 108, con esta solucin s aparecen los
empleados que no tienen oficina.
SELECT numemp, nombre, oficina
FROM empleados
WHERE oficina NOT IN ( SELECT oficina FROM oficinas WHERE dir = 108);

Con la subconsulta obtenemos la lista de las oficinas dirigidas por el empleado


108. Al final se obtienen los empleados cuya oficina no est en esa lista. Pero no
salen los empleados que no tienen oficina asignada ya que su campo oficina es
nulo por lo que el resultado de la comparacin es nulo, no es verdadero y no se
seleccionan. El problema se puede arreglar indicando que tambin se tienen que
seleccionar los empleados con oficina nula:
Solucin 2
SELECT numemp, nombre, oficina
FROM empleados
WHERE ( oficina NOT IN ( SELECT oficina FROM oficinas WHERE dir = 108) ) OR ( oficina IS
NULL);

Con la subconsulta obtenemos la lista de las oficinas dirigidas por el empleado


108. Al final se obtienen los empleados cuya oficina no est en esa lista. Pero no
salen los empleados que no tienen oficina asignada ya que su campo oficina es
nulo por lo que el resultado de la comparacin es nulo, no es verdadero y no se
seleccionan.
SELECT numemp, nombre, oficina
FROM empleados
WHERE oficina <> ALL ( SELECT oficina FROM oficinas WHERE dir = 108);

Con esta solucin tenemos el mismo problema que con NOT IN , cuando la
oficina del empleado es nula todos los resultados de las comparaciones
individuales son nulos por los que el test ALL da nulo y no se seleccionan los
empleados con oficina nula.
Ejercicio 4
SELECT idfab, idproducto, descripcion
FROM productos
WHERE NOT EXISTS (SELECT * FROM pedidos WHERE fab = idfab AND producto = idproducto
AND importe >= 25000);

En este caso es ms cmodo utilizar NOT EXISTS ya que hay que preguntar por el
idfab e idproducto a la vez.
Ejercicio 5
SELECT numclie, nombre
FROM clientes
WHERE repclie IN ( SELECT numemp FROM empleados WHERE nombre = 'Ana Bustamante' )
AND numclie NOT IN ( SELECT clie FROM pedidos WHERE importe > 3000);

Ejercicio 6
SELECT *
FROM oficinas
WHERE EXISTS ( SELECT * FROM empleados WHERE ventas > objetivo * 0.55);

En una subconsulta todos los campos no cualificados se presuponen de la tabla


origen de la subconsulta y slo si no existe ninguna columna con ese nombre, la
considera como referencia externa, por eso no es necesario cualificar ventas
porque interpreta que es el campo ventas de la tabla empleados.
Ejercicio 7
SELECT *
FROM oficinas
WHERE (objetivo * 0.5) <= ALL ( SELECT ventas FROM empleados WHERE empleados.oficina =
oficinas.oficina );

Esta solucin no vale porque salen las oficinas que no tienen empleados.
Hay que aadir una condicin para que se consideren slo las oficinas con
empleados como muestra la solucin 1.
Solucin 1
SELECT *
FROM oficinas
WHERE ((objetivo * 0.5) <= ALL ( SELECT ventas FROM empleados WHERE empleados.oficina =
oficinas.oficina ) )
AND ( EXISTS ( SELECT * FROM empleados WHERE empleados.oficina = oficinas.oficina ) );

Solucin 2
SELECT *
FROM oficinas
WHERE (objetivo * .5) <= (SELECT MIN(ventas) FROM empleados WHERE empleados.oficina =
oficinas.oficina);

Esta es otra posible solucin, calculamos la menor venta de los empleados de la


oficina y si esta es mayor que el 50% del ojetivo de la oficina quiere decir que
todos los empleados de esa oficina tienen ventas iguales o superiores. Si la
oficina no tiene empleados, la subconsulta no devuelve ninguna fila y como
estamos utilizando una comparacin simple el resultado es nulo, luego no salen
las oficinas que no tienen empleados.
Ejercicio 8
SELECT *
FROM oficinas
WHERE objetivo > ( SELECT SUM(cuota) FROM empleados WHERE empleados.oficina =
oficinas.oficina);

Ejercicios tema 6. Actualizacin de datos


Como en estos ejercicios vamos a modificar los valores almacenados en la base
de datos, es conveniente guardar antes una copia de las tablas, en los cuatro
primeros ejercicios crearemos una copia de los datos almacenados para luego
poder recuperar los valores originales.
1 Crear una tabla (llamarla nuevaempleados) que contenga las filas de la tabla
empleados.
2 Crear una tabla (llamarla nuevaoficinas) que contenga las filas de la tabla
oficinas.
3 Crear una tabla (llamarla nuevaproductos) que contenga las filas de la tabla
productos.
4 Crear una tabla (llamarla nuevapedidos) que contenga las filas de la tabla
pedidos.
5 Subir un 5% el precio de todos los productos del fabricante ACI.
6 Aadir una nueva oficina para la ciudad de Madrid, con el nmero de oficina
30, con un objetivo de 100000 y regin Centro.
7 Cambiar los empleados de la oficina 21 a la oficina 30.

8 Eliminar los pedidos del empleado 105.


9 Eliminar las oficinas que no tengan empleados.
10 Recuperar los precios originales de los productos a partir de la tabla
nuevosproductos.
11 Recuperar las oficinas borradas a partir de la tabla nuevaoficinas.
12 Recuperar los pedidos borrados en el ejercicio 8 a partir de la tabla
nuevapedidos.
13 A los empleados de la oficina 30 asignarles la oficina 21.

Solucin ejercicios tema 6. Actualizacin


Ejercicio 1
SELECT * INTO nuevaempleados
FROM empleados;

Ejercicio 2
SELECT * INTO nuevaoficinas
FROM oficinas;

Ejercicio 3
SELECT * INTO nuevaproductos
FROM productos;

Ejercicio 4
SELECT * INTO nuevapedidos
FROM pedidos;

Ejercicio 5
UPDATE productos
SET precio = precio * 1.05 WHERE idfab = 'ACI';

Tambin se puede poner precio = precio + precio*0.05


Ejercicio 6

Solucin 1
INSERT INTO oficinas ( oficina, region, ciudad, objetivo )
VALUES ( 30, 'centro','Madrid', 100000 );

Como no asignamos valor a todos los campos, no hace falta poner todas las
columnas en la lista de columnas. Los campos dir y ventas se rellenarn con el
valor predeterminado.
Ojo! Si la tabla oficinas tiene definido en la columna dir el valor
predeterminado 0, al intentar ejecutar la INSERT ocurrir un error porque asigna
0 al campo dir , como dir es clave ajena, antes de insertar comprueba que el
valor insertado en la clave ajena existe en la tabla empleados, y el empleado 0
no existe por lo que no puede insertar la oficina, el valor predeterminado de dir
debe ser nulo.
Solucin 2
INSERT INTO oficinas (oficina,region,ciudad,dir,objetivo,ventas)
VALUES (30, 'centro', 'Madrid', null, 100000,0) ;

Con esta solucin nos aseguramos que el valor de dir sea nulo
independientemente del valor predeterminado y nos aseguramos que ventas sea
igual a cero.
Solucin 3
INSERT INTO oficinas
VALUES (30, 'Madrid', 'centro', null, 100000,0) ;

En este caso como no especificamos una lista de columnas tenemos que poner los
valores en el mismo orden que las columnas en vista diseo de la tabla.
Ejercicio 7
UPDATE empleados SET oficina = 30 WHERE oficina = 21;

Si ejecutamos esta sentencia antes de haber creado la oficina 30, el sistema nos
devuelve un error.
Ejercicio 8
DELETE FROM pedidos WHERE rep = 105;

Ejercicio 9

Solucin 1
DELETE FROM oficinas WHERE NOT EXISTS (SELECT *
FROM empleados WHERE empleados.oficina = oficinas.oficina);

Si la oficina no tiene empleados asignados, no existe ningn empleado con el


nmero de esa oficina.
Solucin 2
DELETE FROM oficinas WHERE oficina NOT IN (SELECT oficina
FROM empleados) ;

Tambin se puede ver como las oficinas cuyo nmero no se encuentra entre las
oficinas asignados a los empleados.
Solucin 3
DELETE oficinas.*
FROM oficinas LEFT JOIN empleados
ON oficinas.oficina= empleados.oficina
WHERE empleados.numemp IS NULL ;

Otro planteamiento sera unir los empleados con sus oficinas y que tambin
salgan las oficinas que no tienen empleados (por eso LEFT en vez de INNER) a
partir de ah seleccionamos las filas que no tienen valor en el campo numemp,
estas son las no tienen ningn empleado relacionado. Como adems el origen
est basado en dos tablas es obligatorio poner oficinas.* para indicar que se
tienen que borrar las filas de la tabla oficinas y no de empleados.
Ejercicio 10
UPDATE productos INNER JOIN nuevaproductos
ON ( productos.idfab = nuevaproductos.idfab) AND (productos.idproducto =
nuevaproductos.idproducto)
SET productos.precio = nuevaproductos.precio;

Unimos la tabla de productos con la tabla nuevaproductos para tener en una


misma fila el precio que queremos cambiar y el precio antiguo (el valor que
queremos dejar).
Ejercicio 11
INSERT INTO oficinas
SELECT * FROM nuevaoficinas
WHERE oficina NOT IN (SELECT oficina FROM oficinas);

En este caso insertamos en oficinas las oficinas de nuevaoficinas cuyo nmero de


oficina no est en oficinas (es decir las que se han borrado).
Ejercicio 12

INSERT INTO pedidos


SELECT * from nuevapedidos WHERE rep = 105;

Insertamos en pedidos los pedidos del empleados 105 que se encuentran en la


tabla nuevapedidos.
Ejercicio 13
UPDATE empleados
SET oficina = 21 WHERE oficina = 30;

Si no hemos recuperado las oficinas borradas, no permitir cambiar el campo


oficina a 21 ya que la oficina 21 es de las que se han borrado en el ejercicio 9.
Ejercicios tema 7. Referencias cruzadas
1 Queremos saber de cada empleado sus ventas mensuales del ao 1990.
2 Modificar el ejercicio 1 para que junto al nmero de empleado tambin
aparezca el nombre del empleado.
3 Queremos saber las ventas mensuales de cada oficina distinguiendo meses de
distintos aos.
4 Se necesita una estadstica de cuntos empleados fueron contratados por ao
en cada oficina.
5 Queremos saber por ao las ventas realizadas en las distintas regiones.
Solucin ejercicios tema 7. Referencias cruzadas
Ejercicio 1
TRANSFORM SUM(importe)
SELECT rep AS empleado
FROM pedidos
WHERE year(fechapedido)=1990
GROUP BY rep
PIVOT MONTH(fechapedido);

Queremos calcular la suma de importes de los pedidos realizados durante el ao


1990 agrupando por empleado y mes, queremos una fila por empleado luego
GROUP BY rep, queremos que los meses aparezcan como columnas dinmicas,
luego PIVOT MONTH(fechapedido), el calculo se hace en base a los pedidos de
1990 luego el origen de la FROM es pedidos con el WHERE para seleccionar los

pedidos de 1990, como columna fija queremos el nmero de empleado luego la


lista de seleccin ser rep con un alias para que el resultado salga ms aseado.
Ejercicio 2
TRANSFORM SUM(importe)
SELECT numemp AS empleado, nombre
FROM pedidos INNER JOIN empleados ON pedidos.rep=empleados.numemp
WHERE year(fechapedido)=1990
GROUP BY numemp, nombre
PIVOT MONTH(fechapedido);

Ahora queremos que adems aparezca el nombre del empleado, como no est en
la tabla pedidos sino en empleados, hay que aadir a los pedidos los datos del
empleado con el INNER JOIN, ahora queremos dos columnas fijas, la del nmero
de empleado y su nombre luego en la lista de seleccin aadimos nombre, y
como estamos en una sumaria nombre no puede estar en la lista de seleccin si
no est en el GROUP BY luego lo aadimos a la clusula GROUP BY.
Ejercicio 3
TRANSFORM SUM(importe)
SELECT oficina
FROM pedidos RIGHT JOIN empleados ON pedidos.rep=empleados.numemp
GROUP BY oficina
PIVOT year(fechapedido)&"/"&MONTH(fechapedido);

Ahora queremos agrupar por oficina, ao y mes, el pivote sera ao y mes pero
no se pueden poner dos campos en la clusula PIVOT, lo que hacemos es unir los
dos campos en uno mediantela concatenacin & adems para que queden los
valores ms claros los separamos por una barra.
Ejercicio 4
TRANSFORM COUNT(numemp)
SELECT oficina
FROM empleados
GROUP BY oficina
PIVOT year(contrato);

En este caso elegimos como pivote el ao y como encabezado de fila la oficina ya


que normalmente abrn ms oficinas que aos.
Ejercicio 5
TRANSFORM SUM(importe)
SELECT YEAR(fechapedido) AS anyo
FROM (pedidos INNER JOIN empleados ON pedidos.rep=empleados.numemp) INNER JOIN
oficinas ON empleados.oficina=oficinas.oficina
GROUP BY YEAR(fechapedido)
PIVOT region;

En este ejercicios necesitamos los pedidos para el importe vendido y la tabla


oficinas para la regin y para unirlas debemos utilizar la tabla empleados para
relacionar los pedidos con las oficinas de los empleados que han realizado el
pedido.
Ejercicios tema 8. El DDL Lenguaje de Definicin de Datos
Si tienes ya creadas las tablas de los ejercicios del curso y no quieres perder los
datos introducidos cmbiales el nombre antes de empezar los ejercicios de esta
unidad.
1 Crear la tabla empleados y definir su clave principal en la misma instruccin de
creacin.
2 Crear la tabla oficinas con su clave principal y su clave fornea ( la columna dir
contiene el cdigo de empleado del director de la oficina luego es un campo que
hace referencia a un empleado luego es clave fornea y hace referencia a la
tabla empleados).
3 Crear la tabla productos con su clave principal.
4 Crear la tabla clientes tambin con todas sus claves y sin la columna
limitecredito.
5 Crear la tabla pedidos sin clave principal, con la clave fornea que hace
referencia a los productos, la que hace referencia a clientes y la que indica el
representante (empleado) que ha realizado el pedido.
6 Aadir a la definicin de clientes la columna limitecredito.
7 Aadir a la tabla empleados las claves forneas que le faltan. (Si no tienes
claro cuales son te lo decimos ahora: la columna oficina indica la oficina donde
trabaja el empleado y la columna director indica quin dirige al empleado, su
jefe inmediato).

8 Hacer que no puedan haber dos empleados con el mismo nombre.


9 Aadir a la tabla de pedidos la definicin de clave principal.
10 Definir un ndice sobre la columna region de la tabla de oficinas.
10 Eliminar el ndice creado.
Solucin ejercicios tema 8. El DDL
Ejercicio 1
CREATE TABLE empleados (
numemp INTEGER PRIMARY KEY,
nombre TEXT(30) NOT NULL,
edad INTEGER,
oficina INTEGER,
titulo CHAR(20),
contrato DATETIME NOT NULL,
director INTEGER,
cuota CURRENCY,
ventas MONEY);

La solucin propuesta es una de la muchas posibles ya que cada uno puede elegir
el tipo de datos que prefiera siempre y cuando ese tipo permita introducir los
datos que tenemos en las tablas de ejemplo. Tambin la clusula NOT NULL se
puede poner en ms campos de los que tiene la solucin excepto en las columnas
que tengan filas sin valor en las tablas de ejemplo. Por ejemplo en oficina (el
empleado 110 no tiene oficina), en director (el empleado 106 no tiene director) y
en cuota (el empleado 110 no tiene cuota asignada. Pero las columnas edad,
titulo y ventas s las podemos definir con la restriccin NOT NULL. Para definir las
columnas cuota y ventas hemos elegido el tipo moneda (CURRENCY y MONEY son
sinnimos).
Ejercicio 2
CREATE TABLE oficinas (
oficina INT PRIMARY KEY,
ciudad TEXT(30),
region TEXT(20),
dir INT CONSTRAINT cf_dir REFERENCES empleados,
objetivo CURRENCY,
ventas CURRENCY );

Para definir la columna dir como clave fornea hemos elegido una restriccin1
(poner la definicin dentro de la definicin de la columna).
Ejercicio 3

CREATE TABLE productos (


idfab TEXT(10),
idproducto TEXT(20),
descripcion TEXT(30) NOT NULL,
precio CURRENCY NOT NULL,
existencias INT ,
CONSTRAINT cp PRIMARY KEY (idfab,idproducto) );

En este caso la clave principal est formada por dos columnas idfab e idproducto
luego para definirla tenemos que utilizar necesariamente una restriccin2.
Ejercicio 4
CREATE TABLE clientes (
numclie INT ,
nombre TEXT(30) NOT NULL,
repclie INT CONSTRAINT cf_repclie REFERENCES empleados,
CONSTRAINT cp PRIMARY KEY (numclie) ) ;

La clave principal se puede definir en una restriccin2 aunque est compuesta


por una sola columna.
Ejercicio 5
CREATE TABLE pedidos (
codigo COUNTER,
numpedido INT PRIMARY KEY,
fechapedido DATETIME NOT NULL,
clie INT NOT NULL,
rep INT NOT NULL,
fab TEXT(10) NOT NULL,
producto TEXT(20) NOT NULL,
cant INT NOT NULL,
importe CURRENCY NOT NULL,
CONSTRAINT cf_clie FOREIGN KEY (clie) REFERENCES clientes,
CONSTRAINT cf_rep FOREIGN KEY (rep) REFERENCES empleados,
CONSTRAINT cf_prod FOREIGN KEY (fab,producto) REFERENCES productos );

Para exponer ms formas de definir una tabla aqu te hemos definido todas las
claves como restriccin2 la nica que es obligatoria en una restriccin2 es la
cf_prod ya que est compuesta por varias columnas.
Ejercicio 6
ALTER TABLE clientes
ADD COLUMN limitecredito MONEY;

Para aadir una nueva columna a una tabla que ya existe debemos emplear la
sentencia ALTER TABLE, y en nuestro caso la clusula ADD COLUMN (COLUMN es
opcional).

Ejercicio 7
ALTER TABLE empleados
ADD CONSTRAINT cf_oficina FOREIGN KEY (oficina) REFERENCES oficinas,
CONSTRAINT cf_director FOREIGN KEY (director) REFERENCES empleados;

Para aadir una definicin de clave fornea hay que aadir una restriccin2, se
pueden aadir varias restricciones en la misma sentencia ALTER TABLE.
Ejercicio 8
Solucin 1
ALTER TABLE empleados
ADD CONSTRAINT u_nombre UNIQUE (nombre);
Solucin 2
CREATE UNIQUE INDEX u_nombre ON empleados (nombre);

Para que no se puedan repetir los valores en la columna nombre hay que definir
un ndice nico, o bien definiendo una restriccin sobre la columna como te
indicamos en la solucin 1 o bien creando el ndice nico como te indicamos en la
solucin 2.
Ejercicio 9
Solucin 1
ALTER TABLE pedidos
ADD CONSTRAINT cp PRIMARY KEY (numpedido);

Para aadir una definicin de clave primaria hay que aadir una restriccin2.
Solucin 2
CREATE INDEX cp ON pedidos (numpedido) WITH PRIMARY ;

Otra solucin es crear un ndice con la clusula WITH PRIMARY.


Ejercicio 10
CREATE INDEX i_region ON oficinas (region) ;

Ejercicio 11
DROP INDEX i_region ON oficinas ;

UNION

UNION: (OTRO DIA M PONGO A COMPLETAR TODO)

EJERCICIOS:

Se quiere saber que vendedores y clientes hay en la empresa; para los


casos en que su telfono y direccin de e-mail sean conocidos. Se
deber visualizar el cdigo, nombre y si se trata de un cliente o de un
vendedor. Ordene por la tercer columna y la segunda.

select cod_vend, nom_vend, 'vend' Tipo


from vendedores
where nro_tel is not null and

is not null

union
select cod_clie, nom_clie, 'cliente'
from clientes
where nro_tel is not null and

is not null

order by 3,2

Se quiere saber que artculos, clientes y vendedores hay en la


empresa. Determine los campos a mostrar y su ordenamiento

select cod_arti 'Cdigo', descripcion 'Nombre', 'Articulo'Tipo


from articulos

union
select cod_clie, nom_clie, 'Cliente'
from clientes
union
select cod_vend, nom_vend, 'Vendedor'
from vendedores
order by 3

Se quiere saber que artculos hay en la empresa y cules han sido


vendidos. Determine Ud. las columnas a mostrar.

select cod_arti Cdigo, descripcion Articulo, 'En Stock' Tipo


from articulos
union
select D.cod_arti, A.descripcion, 'Vendido'
from detalle D, Articulos A
where D.cod_arti = A.cod_arti
order by 3

Se quiere saber las direcciones tanto de clientes como de vendedores.


Para el caso de los vendedores, cdigos entre 3 y 12. En ambos casos
la direcciones debern ser conocidas. Rotule como NOMBRE,
DIRECCION, INTEGRANTE (en donde indicar si es cliente o vendedor).
Ordenado por la primera columna y la ltima.

select nom_clie Nombre, direccion Direccion, 'Cliente' Integrante


from clientes
where direccion is not null
union
select nom_vend, direccion, 'Vendedor'
from vendedores
where direccion is not null and cod_vend between 3 and 12
order by 1,3

Se quiere saber que clientes hay en la empresa y quienes han


comprado entre el 11/12/2002 y el 27/02/2003. Muestre el cdigo, sin
duplicarlos.

select cod_clie Codigo


from clientes
union
select cod_clie
from facturas
where fecha between 2002-11-12 and 2003-27-02

Idem al ejercicio anterior, slo que adems del cdigo, identifique de


donde obtiene la informacin.

select cod_clie Cdigo, 'Clientes' Desde


from clientes
union all
select cod_clie, 'Facturas'
from facturas F
where fecha between '2002-11-12' and '2003-27-02'

Se quiere saber que clientes hay en la empresa y quines han


comprado; para el primer caso para nombres que empiecen con letras
que van de la c a la l y para el segundo para facturas que oscilen
entre 10 y 23. Muestre el cdigo (no elimine los que se repiten).

select cod_clie Cdigo, 'Pasivo' Tipo


from clientes
where nom_clie like '[c-l]%'
union all
select cod_clie, 'Activo'
from facturas F
where F.nro_factu between 10 and 23

-------------------------------------------------------------------------------------

INNER JOIN

El INNER JOIN: Es otro tipo de composicin de tablas. En lugar de hacer el


producto cartesiano completo, para cada una de las tablas busca directamente
en la otra tabla las filas que cumplen la condicin.
LEFT OUTER JOIN: Toma todos los registros de la tabla izquierda, aunque no
tengan ningn registro coincidente (clave), en la tabla de la derecha.
RIGHT OVER JOIN: Realiza la seleccin de todos los registros de la tabla de la
derecha, aunque NO tenga ningn registros de la tabla de izquierda.

EJERCICIOS:

Liste factura, fecha, vendedor y cliente para las ventas del ao 2006 y
2007.

select f.nro_factu, f.fecha,v.nom_vend, c.nom_clie


from facturas f inner join vendedores v
on f.cod_vend=v.cod_vend
inner join clientes c
on f.cod_clie=c.cod_clie
where year (f.fecha) in (2006, 2007)

Liste cdigo de vendedor, nombre, fecha y factura; para las ventas en


lo que va del ao.

select v.cod_vend, v.nom_vend, f.fecha, f.nro_factu


from facturas f
inner join vendedores v
on f.cod_vend=v.cod_vend
where year(f.fecha)=2007

Liste cdigo de vendedor, nombre, fecha y factura; para las ventas en


lo que va del ao.

select v.nom_vend, v.cod_vend, f.fecha, f.nro_factu


from facturas f
right join vendedores v
on f.cod_vend=v.cod_vend
where year(f.fecha)=2007 or f.fecha is null or f.nro_factu is null

Liste descripcin, cantidad e importe; aun para aquellos artculos que


no registran ventas.

select a.descripcion, d.cant, d.pre_unit, d.pre_unit*d.cant as 'total'


from detalle d
full join articulos a
on d.cod_arti=a.cod_arti
full join facturas f

on d.nro_factu=f.nro_factu
order by a.descripcion

from nombre de talba join otra table on igualamos campos para listar todas las
facturas, y los clientes a los que he facturado para casos en que las facturas no
tengan campo cliente, .
left join es una unin a la izquierda muerto todos los campos de la izquierda y
solo los coicidentes
con la derecha. Con el reight Muesta todos los campos de la derecha y solo los
coicidentes con la derecha Con el full join muestra todos los campos

Liste factura, fecha, vendedor, cliente, articulo, cantidad e importe;


para las ventas de febrero y marzo de los aos 2006 y 2007 y siempre
que el articulo empiece con letras que van de la a a la m. Ordene
por fecha, cliente y articulo.

select f.nro_factu, f.fecha, v.nom_vend, c.nom_clie, a.descripcion,


d.cant, d.pre_unit, d.cant*d.pre_unit
from facturas f full join vendedores v
on f.cod_vend=v.cod_vend
inner join detalle d
on f.nro_factu=d.nro_factu
inner join articulos a
on a.cod_arti=d.cod_arti
inner join clientes c
on f.cod_clie=c.cod_clie
where month(f.fecha)in (2, 3)

and year(f.fecha) in (2006, 2007)

Liste cdigo de cliente,nombre, fecha y factura para las ventas del


ao 2007. Muestre los clientes hayan comprado o no en ese ao.

select c.cod_clie,c.nom_clie, f.fecha, f.nro_factu


from facturas f full join clientes c
on f.cod_clie=c.cod_clie
where year (f.fecha)=2007

Se quiere saber los artculos que compro el cliente 7 en lo que va del


ao. Liste articulo, observaciones e importe.

select a.descripcion, c.nom_clie


from facturas f inner join clientes c
on f.cod_clie=c.cod_clie
inner join detalle d
on f.nro_factu=f.nro_factu
inner join articulos a
on d.cod_arti=a.cod_arti
where c.cod_clie=7
and year(f.fecha)=2007

Se quiere saber los artculos que compraron los clientes que empiezan
con p. Liste cliente, articulo, cantidad e importe. Ordene por cliente

y articulo, este en forma descendente. Rotule como CLIENTE,


ARTICULO, CANTIDAD, IMPORTE.

select c.nom_clie as 'cliente',


a.descripcion as 'articulo' ,
d.cant as 'cantidad',
d.pre_unit as 'precio',
d.cant*d.pre_unit as 'total'
from facturas f inner join detalle d
on f.nro_factu=d.nro_factu
inner join articulos a
on d.cod_arti=a.cod_arti
inner join clientes c
on f.cod_clie=c.cod_clie
where c.nom_clie like '[p]%'
order by c.nom_clie desc, a.descripcion desc

----------------------------------------------------------------------------

SUB-CONSULTAS
Subconsultas: Es una consulta que aparece dentro de la clusula WHERE
HAVING de otra sentencia SQL.
Subconsultas en la clusula WHERE

Test De Comparacin: (= , < , > ) Compara el valor de una expresin con un


nico valor producido por una subconsulta

Test de Pertenencia A Conjunto (IN): Compara un valor de datos con una


columna de valores producida por una subconsulta. NOT IN: esta expresin
significa que no est incluida en la lista de valores generada por la
subconsulta.

Test de Existencia (EXISTS): Comprueba si una subconsulta produce alguna


fila de resultados. Este test slo se utiliza en subconsultas. NOT EXISTS: esta
expresin invierte la lgica.

Test de Cuantificados: ANY y ALL: Ambos tests comparan un valor de datos


con la columna de valores producidos por una subconsulta.

EJERCICIOS:

Se quiere saber que artculos no fueron vendidos el ao pasado y que


el precio unitario del artculo oscile entre 2 y 6. Muestre el nombre del
artculo, observaciones y precio unitario.

select cod_arti, descripcion, observaciones, pre_unit


from articulos
where pre_unit between 2 and 6 and cod_arti not in (select distinct cod_arti
from facturas f, detalle d
where d.nro_factu=f.nro_factu and year(fecha)=2008)

Se quiere saber que clientes vinieron ms de 5 veces el ao pasado.


Muestre el nombre del cliente, nmero de factura y fecha. Rotule
como CLIENTE, FACTURA, FECHA VENTA. Ordene por nombre de cliente
y fecha

select c.cod_clie as COD_CLIENTe, c.nom_clie as CLIENTES ,f.nro_factu as


FACTURAS, f.fecha as FECHA
from clientes c, facturas f
where c.cod_clie=f.cod_clie and year (fecha)=2008 and
5<(select count (*) from facturas f1 where f1.cod_clie=c.cod_clie and
year (fecha)=2008 )
order by c.nom_clie, f.fecha asc

Se quiere saber que clientes vinieron entre el 12/12/2004 y el


13/7/2007. Muestre el nombre del cliente y su direccin de mail.
Ordene por nombre de cliente.

select c.cod_clie, c.nom_clie,


from clientes c
where cod_clie in (select cod_clie from facturas

where fecha between '12/12/2004' and '13/7/2007')

Liste nmero de factura, fecha y cliente para los casos en que todas
las veces que vino a comprar haya sido en el mes de febrero. Ordene
por cliente y fecha.

select distinct c.cod_clie, c.nom_clie,


from clientes c, facturas f
where c.cod_clie=f.cod_clie and fecha between '12/12/2004' and '13/7/2007'

Muestre el nmero de factura y la fecha de venta para los casos en


que por ao se hayan hecho menos de 9 ventas. Rotule como
FACTURA, FECHA VENTA.

select f.nro_factu as FACTURA , f.fecha as FECHA_VENTA


from facturas f
where 9 > (
select count(*)
from facturas f1
where year (f.fecha) = year (f1.fecha) )

Muestre el nmero de factura, la fecha de venta, el artculo y el


importe para los casos en que para esa factura su importe total sea
superior o igual a 150.

select f.nro_factu , f.fecha , a.descripcion , d.pre_unit*d.cant


from facturas f , articulos a , detalle d
where a.cod_arti = d.cod_arti and f.nro_factu = d.nro_factu and 150 < = (
select sum (d1.pre_unit*d1.cant)
from detalle d1
where d1.nro_factu = d.nro_factu)

Se quiere saber que vendedores nunca atendieron a estos clientes:6,


1. Muestre solamente el nombre del vendedor. Rotule como
VENDEDOR.

select *
from vendedores v
where v.cod_vend not in (
select f.cod_vend
from facturas f
where cod_clie in (1,6) )

Se quiere saber de que artculos super el promedio de ventas de 80.


Muestre el nombre del artculo y sus observaciones. Rotule como
ARTICULO, OBSERVACIONES.

select descripcion as ARTICULOS , observaciones as OBSERVACIONES


from articulos a

where 80 < (
select avg (pre_unit*cant)
from detalle d
where a.cod_arti = d.cod_arti)

Que artculos nunca se vendieron?. Tenga adems en cuenta que su


nombre comience con letras que van de la d a la p. Muestre
solamente la descripcin de artculo.

select descripcion
from articulos a
where cod_arti not in (
select distinct d.cod_arti
from detalle d)
and a.descripcion like '[d-p]%'
order by descripcion

-------------------------------------------------

SUB-CONSULTAS CON HAVING

EJERCICIOS:

Se quiere saber la fecha de la primer venta y el importe de ventas por


vendedor, para los casos en que su promedio de ventas sea superior al
importe promedio global. Rotule como VENDEDOR, TOTAL VENTAS.

select nom_vend, min(fecha), sum(pre_unit*cant), avg(pre_unit*cant)


from facturas f, detalle d, vendedores v
where f.nro_factu=d.nro_factu and v.cod_vend=f.cod_vend
group by nom_vend
having avg(pre_unit*cant) > (select avg(pre_unit*cant) from detalle)

Se quiere saber el importe promedio y el importe de ventas por fecha


y cliente, para los casos en que los nmeros de factura que oscilen
entre 20 y 35 y que ese importe de ventas sea superior o igual al
promedio global. Rotule como FECHA VENTA, CLIENTE, IMPORTE,
PROMEDIO.

SELECT fecha, nom_clie, sum(pre_unit*cant), avg(pre_unit*cant)


from facturas f, clientes c, detalle d
where f.nro_factu= d.nro_factu and c.cod_clie = f.cod_clie and f.nro_factu
between 20 and 35
group by fecha, nom_clie, d.cod_arti
having sum(pre_unit*cant) > (select avg(pre_unit*cant) from detalle )

Se quiere saber el importe vendido, la cantidad vendida por artculo,


para los casos en que los nmeros de factura no sean uno de los
siguientes:2, 10, 7, 13, 22 y que ese importe promedio sea inferior al

importe promedio de ese artculo.

SELECT descripcion, sum(d.pre_unit*cant), avg(d.pre_unit*cant)


from articulos a, detalle d
where a.cod_arti = d.cod_arti and nro_factu not in (10,2,7,13,22)
group by descripcion, d.cod_arti
having avg(d.pre_unit*cant) < (select avg(d1.pre_unit*cant) from detalle d1
where d1.cod_arti= d.cod_arti)

Se quiere saber la cantidad vendida, el importe vendido y el promedio


vendido por fecha, siempre que esa cantidad vendida sea superior al
promedio de la cantidad global. Rotule como FECHA VENTA,
CANTIDAD, IMPORTE, PROMEDIO. Ordene por fecha en forma
descendente.

select fecha, sum(cant), sum(pre_unit*cant), avg(pre_unit*cant)


from facturas f, detalle d
where f.nro_factu =d.nro_factu
group by fecha
having sum(cant) > (select avg(cant) from detalle)

Se quiere saber el promedio vendido por fecha y artculo para los


casos en que las cantidades vendidas oscilen entre 5 y 20 y que ese
importe sea superior al importe promedio de ese artculo. Rotule como
FECHA VENTA, ARTICULO, FEC PRIMER VENTA, PROMEDIO.

select fecha, descripcion, avg(d.pre_unit*cant)


from facturas f, articulos a, detalle d
where f.nro_factu = d.nro_factu and a.cod_arti = d.cod_arti and cant between 5
and 20
group by fecha, descripcion, d.cod_arti
having sum(d.pre_unit*cant) > (select avg(d1.pre_unit*cant) from detalle d1
where d1.cod_arti =d.cod_arti)

Se quiere saber el importe vendido por fecha para los casos en que
ese promedio vendido sea inferior al importe promedio global. Rotule
como FECHA, IMPORTE.

SELECT fecha, sum(pre_unit*cant)


from detalle d,facturas f
where f.nro_factu = d.nro_factu
group by fecha
having avg(pre_unit*cant) < (select avg(pre_unit*cant) from detalle)

-------------------------------------------------------------

SUMARIAS

EJERCICIOS:

Se quiere saber la cantidad de clientes que hay en la empresa.

select count (cod_clie) as cantidad


From dbo.clientes

Se quiere saber la cantidad de artculos que hay en la empresa.

select count (cod_arti) as cantidad


from dbo.articulos

Se quiere saber que cantidad de vendedores hay en la empresa.

select count (cod_vend) as cantidad


from dbo.vendedores

Se quiere saber la cantidad de ventas que hizo el vendedor de cdigo


3.

select count (nro_factu) as cantidad


from dbo.facturas
where cod_vend = 3

Se quiere saber la cantidad vendida, la cantidad de ventas y el


importe para la factura 10.

select sum(cant) as 'Cantidad vendida',count (nro_factu) as 'Cantidad de


ventas',sum(pre_unit*cant) as Importe
from dbo.detalle
where nro_factu=10

Se quiere saber cual fue la fecha de la primera y ltima venta. Rotule


como PRIMERVENTA, ULTIMA VENTA.

select max (fecha) as 'ultima venta' , min (fecha) as 'primera venta'


from dbo.facturas

Se quiere saber cual fue la mxima y la mnima cantidad que se


vendi para el artculo 10.

select max(cant) as 'Maxima venta', min (cant) as 'Minima venta'


from dbo.detalle
where cod_arti = 10

Se quiere saber la cantidad total vendida, el monto y el importe


promedio total; para vendedores cuyo nombres comienzan con letras

que van de la d a la l.

select sum (d.cant) as 'Cantidad total vendida' , sum (d.pre_unit) as 'Monto',


avg (d.pre_unit*d.cant) as 'Importe promedio total'
from dbo.detalle d, dbo.vendedores v
where v.nom_vend like '[d-l]%'

Se quiere saber el promedio del importe vendido, el total del importe


vendido, el promedio de la cantidad vendida y el total de la cantidad
vendida.

select avg(pre_unit*cant) as 'Promedio importe', sum(pre_unit*cant) as


'Importe total', avg(cant) as 'Promedio cantidad vendida', sum(cant) as 'Total
cantidad vendida'
from dbo.detalle

Se quiere saber el total vendido, el promedio vendido y la cantidad


total vendida para el cliente de cdigo 3.

select sum(d.cant) as 'Total vendido', avg(d.cant) as 'Promedio vendido'


from dbo.detalle d, dbo.clientes c
where c.cod_clie = 3

Se quiere saber la fecha de la primera venta, la cantidad total vendida


y el monto total vendido para los artculos que empiecen con c.

select min(f.fecha) as 'Fecha primer venta', sum(d.cant) as 'Cant total vendida',

sum(d.pre_unit) as 'Monto total'


from dbo.facturas f, dbo.detalle d, dbo.articulos a
where a.descripcion like 'c%'

Se quiere saber la cantidad total vendida y el monto total vendido


para el periodo del 15/06/2005 al 15/03/2007.

select sum(d.cant) as 'Cantidad total ', sum(d.pre_unit*d.cant) as 'Monto total'


from dbo.detalle d, dbo.facturas f
where f.fecha between '15/06/2005' and '15/03/2007'

Se quiere saber la cantidad de veces y la ltima vez que vino el cliente


de apellido Abarca.

select count(f.nro_factu) as 'Cantidad de veces' , max(f.fecha) as 'Ultima visita'


from dbo.facturas f , dbo.clientes c
where c.nom_clie like 'Abarca%'

Se quiere saber el importe total vendido y el importe promedio


vendido para nmeros de factura que no sean los siguientes: 13, 5,
17, 33, 24.

select sum(d.cant*pre_unit)as 'Importe total' , avg(d.cant*d.pre_unit) 'Importe


promedio'
from dbo.detalle d, dbo.facturas f
where d.nro_factu= f.nro_factu and f.nro_factu not in (13,5,17,33,29)

----------------------------------------------------

VISTAS

EJERCICIOS:

Cree las siguientes vistas:

Detalle_Ventas_Vendedor: Liste la fecha, la factura, el codigo y


nombre del vendedor, el articulo, la cantidad e importe, para lo que va
del ao. Rotule como FECHA, NRO_FACTURA, CODIGO_VENDEDOR,
OMBRE_VENDEDOR, ARTICULO, CANTIDAD, IMPORTE.

create view [Detalle_ventas_vendedor]


as (

select f.fecha as FECHA, f.nro_factu as NRO_FACTURA, v.cod_vend as


CODIGO_VENDEDOR,
v.nom_vend as NOMBRE_VENDEDOR, a.descripcion as ARTICULO,
d.cant as CANTIDAD, (d.pre_unit*d.cant) as IMPORTE
from facturas f, vendedores v, articulos a, detalle d
where year (fecha) = 2009)

select *
from [Detalle_ventas_vendedor]

Subtotales_Ventas_Vendedor: Se quiere saber el importe vendido y la


cantidad de ventas por vendedor. Rotule como VENDEDOR,
IMPORTE_VENDIDO, CANTIDAD_VENDIDA.

create view [subtotales_ventas_vendedor]


as (
select count (v.cod_vend) as CANTIDAD_VENTAS, v.nom_vend ,
sum(d.pre_unit*d.cant) as IMPORTE
from facturas f, detalle d, vendedores v
where f.cod_vend = v.cod_vend and f.nro_factu = d.nro_factu
group by v.nom_vend )

select *
from [subtotales_ventas_vendedor]

Modifique las vistas segn el siguientes detalle:


La vista creada en el punto b, agrguele la condicin de que solo tome
lo del ao en curso y que tambin muestre el promedio vendido y el
cdigo del vendedor.

alter view [subtotales_ventas_vendedor]


as (
select count (v.cod_vend) as CANTIDAD_VENTAS, v.nom_vend ,
sum(d.pre_unit*d.cant) as IMPORTE,
avg(d.pre_unit*d.cant) as PROMEDIO_VENDIDO,
v.cod_vend
from facturas f, detalle d, vendedores v
where f.cod_vend = v.cod_vend and f.nro_factu = d.nro_factu and year (fecha)
= 2009
group by v.nom_vend, v.cod_vend)

select *
from [subtotales_ventas_vendedor]

Consulta las vistas segn el siguiente detalle:


Llame a la vista creada en el punto 1.a pero filtrando por importes
inferiores a $20.

select *
from [Detalle_ventas_vendedor]

where IMPORTE <= 20

Llame a la vista creada en el punto 1.b filtrando para el vendedor


Miranda.

select *
from [subtotales_ventas_vendedor]
where nom_vend like 'Miranda%'

Llama a la vista creada en el punto 1.b filtrando para promedios


superiores a 100.

select *
from [subtotales_ventas_vendedor]
where PROMEDIO_VENDIDO > 40

Elimine las vistas creadas en el punto 1 (no se olvide de colocar el


nombre como corresponde)

drop view [Detalle_ventas_vendedor]


drop view [subtotales_ventas_vendedor]

----------------------------------------------------

PROCEDIMIENTOS
ALMACENADOS

EJERCICIOS:

Cree los siguientes SP:


LEGAJO-Detalle_Ventas: liste la fecha, la factura, el vendedor, el
cliente, el artculo, cantidad e importe. Este SP recibir como
parmetros de E un rango de fechas.
create procedure detalle_venta
@fecha1 as smalldatetime,
@fecha2 as smalldatetime
as
select f.fecha, f.nro_factu, v.nom_vend, c.nom_clie, a.descripcion, d.cant,
(d.cant*d.pre_unit)
from clientes c, facturas f, vendedores v, articulos a, detalle d
where f.nro_factu = d.nro_factu and c.cod_clie = f.cod_clie and
a.cod_arti = d.cod_arti and v.cod_vend = f.cod_vend and
fecha between @fecha1 and @fecha2
execute detalle_venta '20/03/2008','13/11/2009'
CantidadArt_Cli : este SP me debe devolver la cantidad de artculos o
clientes (segn se pida) que existen en la empresa.
create procedure CantidadArt_Clie
@opcion1 int
as
begin
if (@opcion1 = 1)
select count (*) from Articulos as Articulos
else
select count (*) from Clientes as Clientes
end

execute CantidadArt_Clie '1'

INS_Vendedor: Cree un SP que le permita insertar registros en la tabla


vendedores.
create procedure INS_Vendedores
@cod_vend as int output,
@nom_vend as nvarchar (50),
@dir as nvarchar (50),
@nro_tel as int,
@e_mail as nvarchar (50),
@fec_nac as smalldatetime
as
begin
insert into vendedores (nom_vend, direccion, nro_tel, fec_nac) values
(@nom_vend, @dir, @nro_tel, @fec_nac)
set @cod_vend = @@identity
end
declare @a as int
execute INS_Vendedores
@a output, 'Pedro Perez', 'Lavalleja 250', 4205889, null, '20/03/2001'
UPD_Vendedor: cree un SP que le permita modificar un vendedor
cargado.
create procedure UPD_Vendedor
@cod_vend int,
@nom_vend nvarchar (50),
@dir nvarchar (50),
@nro_tel int,
@correo nvarchar (50),
@fec_nac smalldatetime
as
update vendedores
set nom_vend = @nom_vend,
direccion = @dir,
nro_tel = @nro_tel,
= @correo,
fec_nac = @fec_nac
where cod_vend = @cod_vend

execute UPD_Vendedor
12, 'Pedro Perez', 'Lavalleja 250', 4205889, null, '20/03/2001'

DEL_Vendedor: cree un SP que le permita eliminar un vendedor


ingresado.
create procedure DEL_Vendedores
@cod_vend as int
as
delete from vendedores
where cod_vend = @cod_vend
exec DEL_Vendedores
'13'

Potrebbero piacerti anche