Professional Documents
Culture Documents
APRENDESQL
G. Quintana, M. Marqus,
J. l. Aliaga, M. J. Aramburu
UNIVERSITAT
.JAUMEI
ndice
,
PROLOGO .............................................................................................................. 1
,
1 IN"TRODUCCION .............................................................................................. 5
1.1 ORIGEN Y DIFUSIN DE LAS BASES DE DATOS ................................................. 5
1.2 CONCEPTOS BSICOS DE LOS SISTEMAS RELACIONALES ................................. 7
1.3 EL LENGUAJE SQL........................................................................................... 8
1.3.1 Partes de SQL .......................................................................................... 9
1.3.2 Sentencias del Lenguaje de Manipulacin de Datos ............................. 10
1.3 .3 Orgenes y estndares ............................................................................ 1O
1.4 BASE DE DATOS DE EJEMPLO ......................................................................... 11
,
5 AGRUPACION ................................................................................................. 53
5.1 MOTIVACIN. INTRODUCCIN ...................................................................... 53
5.2 FUNCIONES DE GRUPO ................................................................................... 56
5.3 TIPOS DE AGRUPACIONES ............................................................................. 56
5.4 AGRUPACIONES POR MLTIPLES FACTORES ......................... :........................ 57
5.5 AGRUPACIONES INCORRECTAS ...................................................................... 58
5.6 RESTRICCIONES DE FILA Y RESTRICCIONES DE GRUPO .................................. 59
5. 7 EJECUCIN DE UNA CONSULTA CON AGRUPACIN ........................................ 61
5.8 COMBINACIN DE FUNCIONES DE GRUPO Y FUNCIONES DE COLUMNA ....... 62
5.9 REGLAS NEMOTCNICAS ............................................................................... 63
5.1 oEJERCICIOS .................................................................................................. 63
5.11 AUTOEVALUACIN ...................................................................................... 66
6 CONCATENACIN INTERNA DE TABLAS .............................................. 67
6.1 CONCATENACIN INTERNA DE DOS TABLAS ................................................. 67
6.2 ALIAS DE TABLAS .......................................................................................... 69
6.3 SINTAXIS ESTNDAR ..................................................................................... 70
6.3.1 Operador A natural jo in B ..................................................................... 70
6.3.2 Operador A [inner] join B using ( lista_columnas) .............................. 71
PRLOGO
La presentacin del lenguaje SQL tiene en este texto un enfoque muy prctico y
aplicado. Se han incluido numerosos ejemplos y ejercicios al lado de cada
concepto nuevo introducido para que de esta forma el lector pueda practicar y ver
en la prctica cada concepto que se describe. De hecho, la mayor parte de los
captulos incluyen ms de 20 ejercicios. Los ejercicios se presentan siempre con
solucin para que el lector pueda contrastar sta con la suya o estudiarla sin ms.
Las soluciones se dan inmediatamente tras la propuesta para evitar al lector la
labor de ir al final del texto tras cada ejercicio a buscar la solucin en un apndice
final. nicamente se han llevado a un apartado final las soluciones de los
ejercicios de autoevaluacin dado su carcter ms evaluador y menos didctico.
Estos ejercicios, que ya no incluyen ayuda alguna, deben realizarse cuando el
lector haya resuelto satisfactoriamente todos los anteriores.
Este texto est casi principal, aunque no exclusivamente, dedicado a la
sentencia de recuperacin de datos select, dado que es con mucho la ms
compleja. A su lado, las otras resultan simples reducciones o simplificaciones
suyas. Esta sentencia presenta tres conceptos muy importantes sobre los que se
sustenta la potencia del lenguaje SQL: la agrupacin, la concatenacin de tablas y
las subconsultas. Estos conceptos se introducirn poco a poco con numerosos
ejemplos.
El contenido de este libro puede agruparse en varias partes, cada una de las
cuales se descompone en uno o ms captulos. A continuacin se presentan
brevemente cada una de las partes y cada uno de los captulos que las componen.
La primera parte es, obviamente, una introduccin general al mundo de las
bases de datos y una introduccin muy bsica y rudimentaria al lenguaje
SQL.
o El captulo 1 realiza una presentacin general del mundo de las bases de
datos relacionales, repasando su pasado, presente y futuro, y del lenguaje
SQL. Finalmente presenta el ejemplo de base de datos que se va a
emplear a lo largo de todo el texto.
o El captulo 2 inicia al lector en el lenguaje SQL y, concretamente, en la
sentencia de recuperacin de datos.
o El captulo 3 describe un conjunto de funciones y operadores que
permiten realizar clculos avanzados como por ejemplo las conversiones
de tipos, extracciones de partes de una fecha, comparaciones avanzadas,
diversas operaciones matemticas, etc.
La segunda parte comienza ya a profundizar en el lenguaje SQL presentando
las funciones de columna y el concepto de agrupacin.
o El captulo 4 introduce las funciones de columna que suele incluir SQL.
Estas son funciones que resumen toda una columna de una tabla en un
solo valor, como por ejemplo, la suma, el mximo, la media, etc.
1 INTRODUCCIN
APRENDESQL
INTRODUCCIN
Tabla CLIENTES
Cada fila contiene informacin sobre una nica instancia de una entidad. Por
ejemplo, cada fila de la tabla facturas contiene informacin sobre una factura.
Cada columna contiene informacin sobre una nica propiedad o atributo de las
entidades. Por ejemplo, la columna nombre de la tabla clientes contiene los
nombres de los clientes.
Una celda es una interseccin de una fila y de una columna. Cada celda puede
contener bien un valor o bien ningn valor. Cuando no contiene ningn valor, se
dice que tiene el valor nulo. El valor nulo puede tener dos orgenes: un valor
desconocido o un valor no aplicable. Por ejemplo, la tabla de facturas tiene un
valor nulo en la fecha de la factura con cdigo 32.
Las filas de las tablas no estn ordenadas ni tienen una posicin fija. Por tanto,
no se puede acceder a una determinada informacin de una tabla a travs de su
posicin en la tabla (tercera fila, vigsima fila, etc.). Para acceder a una entidad
hay que conocer alguna de sus propiedades o atributos.
La clave primaria es una columna o conjunto de columnas que identifican de
forma nica a cada una de las entidades (filas) que componen las tablas. En Access
se la denomina clave principal a esta clave.
APRENDESQL
INTRODUCCIN
10
APRENDESQL
INTRODUCCIN
11
En 1992 ANSI e ISO publicaron una nueva revtston del estndar SQL,
conocido oficialmente como X3.135-1992 e ISO/lEC 9075:1992 e informalmente
como SQL-92 o SQL2. Este estndar clasifica todas las caractersticas del lenguaje
en varios niveles: Entry SQL, Transitional SQL, Intermediate SQL y Full SQL.
X/Open acept el estndar de nivel ms bajo, el Entry SQL, y diversas
caractersticas del Intermediate SQL. Este estndar ocupa alrededor de 600
pginas.
El estndar SQL ha continuado evolucionando hasta hoy en da. Como una
revisin y ampliacin del estndar SQL-92 surgi el estndar SQL-99 o SQL3.
Este ya no consta de niveles sino del ncleo (Core SQL) y de una parte no nuclear.
Posee ciertos aspectos orientados a objetos. Este estndar ocupa alrededor de 2200
pginas.
El estndar SQL-2003 est ya ms orientado hacia sistemas
relacionales/orientados a objetos. Tanto las especificaciones de este estndar como
las del anterior no estn libremente disponibles, sino que se deben comprar a las
organizaciones ANSI o ISO.
De todas formas, los distintos creadores de SGBD, tanto comerciales como no
comerciales, que incluyen SQL no se han distinguido especialmente por su gran
tradicin en seguir los estndares, sino todo lo contrario. Ms concretamente,
dicen que siguen el estndar de turno, dicen que incluso aportan diversas
caractersticas no incluidas en el estndar y, despus, en letra ms pequea, dicen
que algunas caractersticas del estndar no han sido incluidas. En resumen, han
tomado del estndar de la fecha solamente lo que han querido y han aadido
cuantas cosas han credo conveniente, incluso a veces sin respetar la sintaxis
original propuesta en el estndar.
De hecho, a fecha de hoy algunos de los productos comerciales ms vendidos y
desarrollados por empresas consideradas muy serias an no cumplen
completamente el estndar SQL-92.
12
APRENDESQL
13
INTRODUCCIN
Se puede observar que el cdigo de pueblo es una tira de 5 caracteres. Las tres
columnas no aceptan nulos.
Tabla Clientes
APRENDESQL
14
Tabla Vendedores
INTRODUCCIN
15
2 INICIACIN A SQL
from provincias;
18
APRENDESQL
select codpro, nombre
from
provincias;
precio
* (
1 - dto
100 )
1 columna!, columna2,
columna3, ...
INICIACIN A SQL
19
! Ejercicio: Mostrar el cdigo de factura y fecha de las facturas con iva 16 y del
cliente 100.
Solucin:
select codfac, fecha
from
facturas
20
APRENDESQL
where
and
iva
16
codcli
100;
: Ejercicio: Mostrar el cdigo y fecha de las facturas del cliente 100 tales que
tienen iva 16 o descuento 20.
Solucin:
select
from
where
and
or
codfac, fecha
facturas
codcli
100
( iva
16
dto
20 );
=
=
=
2.5 Ejercicios
: Ejercicio 2.1: Mostrar el cdigo de artculo y la cantidad de las lneas de la
factura cuyo cdigo es 105.
Solucin:
select codart, cant
from
lineas_fac
where codfac
105;
INICIACIN A
SQL
21
codart, precio
articules
precio > 2.05
stock > 100;
codart, cant
lineas_fac
dto
10
precio > 5.05;
: Ejercicio 2.4: Tipos de descuentos aplicados en las facturas del cliente 222.
Solucin:
select distinct dto
from
facturas
where codcli
222;
2.6 Autoevaluacin
! Ejercicio 1: Mostrar el cdigo y nombre de aquellos vendedores cuyo jefe
tiene el cdigo 125.
Este captulo presenta las funciones y operadores escalares del lenguaje SQL.
Son funciones que devuelven un valor modificado por cada valor inicial. Dado el
elevado nmero de funciones y operadores que contienen tanto el estndar como
las distintas implementaciones, en este captulo se describen nicamente los ms
importantes. En Internet y en los manuales de referencia se pueden encontrar listas
ms exhaustivas.
En el caso de ls funciones y operadores escalares la variacin entre los
distintos SQL es bastante alta. Afortunadamente, dado que estas funciones no son
excesivamente complicadas, pasar de una implementacin de SQL a otra no cuesta
demasiado tiempo. Es ms, en muchos casos se tratan de los mismos conceptos
pero con nombres distintos. En el resto del captulo se van a describir las funciones
y operadores escalares ms importantes tanto del estndar SQL-99 como de varias
implementaciones comerciales de SQL.
APRENDESQL
24
Otro error frecuente es operar con valores enteros (sin decimales) cuando en
realidad se desea trabajar con valores reales (con decimales). En algunos sistemas
la operacin 113 devuelve cero pues tanto el numerador como el denominador son
enteros y, por tanto, se aplica la divisin entera. Si se desea trabajar con nmeros
reales puede realizarse con una operacin de conversin explcita o bien aadiendo
una parte fraccionaria. Si se desea realizar una divisin real, debera escribirse la
instruccin 1.0/3.0.
25
: Ejercicio: Escribir una expresin que devuelva todas las columnas de los
artculos cuyo stock no se halla entre el stock mnimo menos 500 unidades y el
stock mnimo ms 500 unidades.
Ayuda: Uso del operador not between y del carcter * en la clusula select.
Solucin:
select *
from
articulos
where stock not between
stock_min - 500 and stock_min + 500;
3.2.2 Operador in
Su funcionamiento es muy sencillo: a in ( b, e, d,., z ) devuelve cierto si a es
igual a alguno de los valores incluidos en la lista entre parntesis (b, e, d,..., z) y
devuelve falso en caso contrario. La siguiente lnea resume su funcionamiento:
a in ( b, e, d) equivale a (a= b) or (a= e) or (a= d).
El funcionamiento del operador not in es justo el contrario: a not in ( b, e, d,...,
z ) devuelve cierto si a no es igual a ninguno (o sea, es distinto de todos) de los
valores incluidos en la lista entre parntesis (b, e, d, , z) y devuelve falso en caso
contrario. La siguiente lnea resume su funcionamiento:
a not in ( b, e, d) equivale a (a<> b) and (a<> e) and (a<> z).
Su funcionamiento es completamente idntico en los distintos SQL de SQL-99,
Access, Oracle, PostgreSQL y MySQL.
'12',
'46' );
APRENDESQL
26
3.2.3 Operador like
27
end
facturas
dto = 20;
= 16
=
then 'normal'
7 then 'reducido'
else 'otros'
APRENDESQL
28
"mayor", "normal"
o En Oracle 8i:
decode( sign(precio-100), 1,
'mayor',
'normal' )
Switch. Esta funcin suele ser menos til que la funcin Iif. Debe tener un
nmero par de parmetros. Si el primer parmetro es cierto, se devuelve el
segundo y se termina; en caso contrario, si el tercer parmetro es cierto, se
devuelve el cuarto y se termina; y as sucesivamente. Para devolver un valor
final si no se cumple ninguna de las condiciones anteriores, se pone como
29
o En Oracle 8i:
decode( iva, 16,
'normal', 7,
'reducido',
'otro' )
o En Oracle 8i:
decode( modoPago, 1, 'efectivo', 2,
3, 'tarjeta')
'cheque',
30
APRENDESQL
IsNull.
31
EnAccess:
IsNull( dto
En Access:
Not IsNull( dto )
! Ejercicio: Escribir una sentencia que muestre los cdigos y fechas de aquellas
facturas sin cdigo de cliente o sin cdigo de vendedor.
Solucin:
select
from
where
or
codfac, fecha
facturas
codcli is null
codven is null;
codart
articules
( stock > 50 )
(stock is null);
APRENDESQL
32
desconocido). La tercera sentencia recupera los artculos cuyo stock supera las
50 unidades o es desconocido, es decir, devuelve aquellos artculos que
podran tener un stock superior a 50.
En Access:
Nz( dto, O )
! Ejercicio: Escribir una sentencia que muestre los cdigos de aquellos artculos
(sin mostrar repetidos) vendidos alguna vez sin descuento en sus lneas de
facturas. Se considera que un artculo no tiene descuento cuando ste es cero o
nulo.
Solucin:
select distinct codart
from
lineas_fac
where coalesce( dto, O )
= O;
33
Solucin:
select codfac, fecha, coalesce( dto, O )
from
facturas
where coalesce( iva, O ) = O;
34
APRENDESQL
Por ejemplo, la siguiente sentencia:
select to_number( '123' ),
to_number( to_char( 12345 ) )
from
dual;
EnAccess:
Date()
EnAccess:
'yyyy' )
35
En los apndices se pueden encontrar varias tablas con los distintos formatos
ms habituales permitidos en las funciones extract y to_char.
Por ejemplo, para seleccionar las facturas del ao pasado, se debera usar la
clusula siguiente:
where
! Ejercicio: Escribir una expresin que devuelva el nmero del mes actual.
Ayuda: Uso de la funcin extract con el formato de fecha month, de la funcin
current_date y la tabla dual.
Solucin:
select extract( month from current_date
from
dual;
=
=
! Ejercicio: Escribir una expresin que devuelva el cdigo de los clientes que
tengan alguna factura durante el ltimo trimestre del ao pasado.
Ayuda: En el estndar, la extraccin del trimestre de una fecha puede
realizarse fcilmente con la expresin extract( quarter from fecha), pero
Oracle lOg no soporta el formato quarter, por lo que hay que recurrir a la
orden to char.
Solucin:
select distinct codcli
from
facturas
where to_char( fecha, 'q' )
= '4'
APRENDESQL
36
and
'dd-mm-yyyy'
EnAccess:
Format( fecha, "dd-mm-yyyy" )
Estas dos funciones anteriores tambin sirven para extraer una parte de una
fecha, como por ejemplo el nombre del mes, si se emplea la tira de caracteres
adecuada (ver apndices). De esta forma, pueden servir para completar a la funcin
extract anteriormente descrita.
Ambas funciones devuelven tiras de caracteres como resultado, el cual deber
ser convertido en entero si se desea operar matemticamente con l.
Como se puede ver, todas las funciones de procesamiento de fechas son
distintas, pero conceptualmente muy semejantes.
EnAccess:
DateValue( '28-febrero-2008'
37
'yyyyddmm' )
En Oracle:
length ( tira
En Access:
Len( tira )
! Ejercicio: Escribir una expresin que devuelva la longitud del nombre de cada
cliente cuyo cdigo se encuentre comprendido entre 100 y 200, inclusive.
APRENDESQL
38
Solucin: Se emplea la sintaxis de Oracle.
select length( nombre )
from
clientes
where codcli between 100 and 200;
En Oracle:
substr( tira, 2, 3 )
EnAccess:
Mid( tira, 2, 3 )
En este sistema existen tambin las funciones Left y Right para extraer un
determinado nmero de caracteres desde la izquierda o desde la derecha.
: Ejercicio: Escribir una expresin que devuelva el cdigo y nombre de aquellos
vendedores cuya ltima letra del nombre es una 'E'.
Solucin: Se emplea la sintaxis de Oracle.
select codven, nombre
from
vendedores
where substr( nombre, length( nombre), 1
'E';
En Access:
39
ucase( tira
lcase( tira
APRENDESQL
40
precio importe
Oracle no permite saltar la clusula from, pero ofrece una minitabla con una
fila y una columna que permite trabajar con datos inmediatos. Por ejemplo:
select round( 300.199, 2 ) from dual;
select substr( 'mapas', 2, 2) from dual;
! Ejercicio: Escribir una consulta que muestre el nombre de los clientes cuyo
cdigo postal empieza por "02", "11" o "21 ".
Ayuda: Uso del operador in y de la funcin substr.
Solucin:
select nombre
from
clientes
where substr( codpostal, 1, 2
1 02 1 ,
1 11' ,
1 21'
(
);
41
in
3.11 Ejercicios
! Ejercicio 3.1: Cdigo, fecha y descuento de las facturas cuyos cdigos se
encuentren entre 100 y 150. Visualizar el valor -100 en la columna descuento
si ste es nulo.
Solucin:
select codfac, fecha, coalesce( dto, -100 )
from
facturas
where codfac between 100 and 150;
! Ejercicio 3.2: Cdigo y fecha de aquellas facturas del ao pasado cuyo iva es
nulo.
Solucin: La siguiente consulta se ha escrito con la sintaxis de Oracle.
select
from
where
and
codfac, fecha
facturas
iva is null
extract( year from fecha ) =
extract( year from current_date ) - 1;
! Ejercicio 3.3: Mostrar el cdigo y la fecha de las facturas del ltimo trimestre
del ao pasado para aquellos clientes cuyo cdigo se encuentra entre 50 y 100.
Ayuda: Uso del formato de fecha q para extraer el trimestre.
Solucin:
select
from
where
and
and
codfac, fecha
facturas
codcli between 50 and 100
to_char( fecha, 'q' ) = '4'
extract( year from fecha )
extract( year from current_date
- 1;
APRENDESQL
42
else 1
from
where
end
artculos
codart like 'A%';
! Ejercicio 3.5: Cdigos de los clientes, sin que salgan repetidos, a los que se les
ha hecho alguna factura sin iva (iva cero o nulo).
Solucin:
select distinct codcli
from
facturas
where coalesce( iva, O )
= O;
! Ejercicio 3.6: Cdigo y nombre de aquellos clientes cuyo nombre termina con
la tira "ez".
Solucin: Se usa la sintaxis de Oracle.
select codcli, nombre
from
clientes
where substr( nombre, length( nombre )-1, 2) = 'ez';
from
where
43
clientes
codpostal like '11%';
! Ejercicio 3.9: Se desea promocionar los artculos de los que se posee un stock
grande. Si el artculo es de ms de 30 euros y el stock supera los 300 euros, se
har un descuento del 10%. Si el artculo es de 30 euros o menos y el stock
supera los 150 euros, se har un descuento del 15%. Mostrar un listado de los
artculos que van a entrar en la promocin, con su cdigo de artculo, precio
actual y su precio en la promocin.
Ayuda: Uso del operador case. El precio del artculo sirve para discernir entre
un caso y otro.
Solucin:
select codart, precio,
round( precio *
case when (precio > 30) then 0.9
else 0.85
end, 2
from
articulos
where ( precio > 30 and stock * precio > 300 )
or
(precio<= 30 and stock* precio> 150 );
3.12 Autoevaluacin
! Ejercicio 1: Pueblos de la provincia de Castelln cuya primera y ltima letra
coinciden.
FUNCIONES DE COLUMNA
Este captulo presenta las funciones de columna del lenguaje SQL. Son
funciones que resumen toda una columna en un nico valor, de ah su nombre.
En los ejemplos siguientes se emplearn obviamente las diversas tablas
descritas en el primer captulo. Para ilustrar algunos ejemplos de forma ms
concreta se considerar la tabla de artculos rellenada de la siguiente forma:
Tabla ARTICULOS
La sentencia anterior devuelve como resultado una lnea con el precio por cada
artculo existente en la tabla de artculos. En la tabla de artculos con el contenido
mostrado al principio del captulo, el resultado son los valores 1, 2, 2, nulo y 3.
En cambio, una sentencia select con al menos una funcin de columna devuelve
una nica lnea para toda la tabla: Es decir, resume toda la tabla en un nico valor.
Por ejemplo:
select avg( precio
from
articulos;
46
APRENDESQL
La sentencia anterior devuelve como resultado una nica lnea con un valor: la
media del precio de los artculos. Es decir, resume todos los descuentos en un
nico valor. En la tabla de artculos con el contenido mostrado al principio del
captulo, el resultado es 2 euros (dado que se ignoran los valores nulos).
Hay que distinguir entre funciones normales (o funciones escalares) y
funciones de columna. Una funcin normal (substr, round, etc.) devuelve un valor
modificado por cada valor de la tabla original. Por ejemplo:
select sqrt( precio )
from
articules;
FUNCIONES DE COLUMNA
47
! Ejercicio: Escribir una sentencia que obtenga el stock ms alto para aquellos
artculos cuyo precio no supera los 2 euros.
Solucin:
select max( stock )
from
facturas
where precio <= 2.00;
APRENDESQL
48
! Ejercicio: Escribe una sentencia que calcule el stock medio de los artculos.
Solucin:
49
FuNCIONES DE COLUMNA
! Ejercicio: Escribe una sentencia que calcule el stock medio de los artculos,
pero considerando los nulos como ceros.
Solucin: En principio la funcin avg ignora los valores nulos. Para evitarlo
hay que convertir dichos valores al valor cero antes de calcular la media.
select avg( coalesce( stock, O ) )
from
articules;
Otra posible solucin consiste en calcular la suma de todos los precios (esta
operacin ignorar los valores nulos) y dividir por el total de artculos.
select sum( stock ) 1 count(
from
articules;
* )
APRENDE
50
SQL
= 3;
4.6 Ejercicios
! Ejercicio 4.1: Escribir una sentencia que calcule el nmero de artculos cuyo
stock es nulo.
Ayuda: Uso de la funcin de columna count.
51
FUNCIONES DE COLUMNA
Solucin:
select count( * )
from
articulos
where stock is null;
! Ejercicio 4.3: Escribir una sentencia que calcule el nmero de clientes sin
cdigo postal. No se debe emplear la clusula where.
Ayuda: Calcular el nmero total de clientes y restar el nmero de clientes que
s tienen cdigo postal.
Solucin:
select count( *
from
clientes;
) -
count( codpostal )
! Ejercicio 4.4: Escribir una sola sentencia que calcule el nmero de facturas
con iva 16, el nmero de facturas con iva 7 y el nmero de facturas con otros
ivas.
Ayuda: El nmero de facturas con iva 16 se puede calcular sumando el
resultado de convertir los ivas 16 en unos y el resto en ceros usando la
expresin case. El resto de informacin se puede calcular de forma anloga.
Solucin:
select sum( case iva when 16 then 1 el se o end ) ,
sum( case iva when 7 then 1 el se o end ) ,
sum( case iva when 16 then o when 7 then O
el se 1 end )
from
facturas;
APRENDESQL
52
Solucin:
select
from
: Ejercicio 4.6: Escribir una sentencia que calcule el nmero medio mensual de
facturas realizadas durante el ao pasado por el vendedor con cdigo 400.
Ayuda: El nmero medio mensual se calcula a partir del nmero anual de
facturas dividido entre 12 meses. Si se emplea 12 como divisor, entonces el
resultado ser un entero (dado que el dividendo y el divisor son ambos enteros)
y pueden perderse decimales. En cambio, si se usa 12.0 como divisor, el
resultado ser un nmero real con varios decimales (cuyo nmero podria
limitarse con la funcin round).
Solucin: La siguiente consulta se ha escrito con la sintaxis de Oracle.
select count( * ) 1 12.0
from
where
and
facturas
codven = 400
extract( year from fecha )
extract( year from current_date ) - 1;
: Ejercicio 4.7: Escribir una sentencia que calcule el nmero de vendedores que
han realizado al menos una factura durante el ao pasado. .
Ayuda: Es conveniente eliminar las filas repetidas.
Solucin: La siguiente consulta se ha escrito con la sintaxis de Oracle.
select count( distinct codven )
from
facturas
where extract( year from fecha ) =
extract( year from current_date ) - 1;
4. 7 Autoevaluacin
: Ejercicio 1: Escribir una sentencia que calcule el nmero mximo de lneas en
una factura.
: Ejercicio 2: Escribir una sentencia que calcule el nmero de facturas sin
descuento (cero o nulo); con descuento moderado ( <= 10) y con descuento
elevado ( > 10 ).
: Ejercicio 3: Escribir una sentencia que calcule el nmero medio de unidades
vendidas en una lnea de factura.
5 AGRUPACIN
Este captulo presenta la agrupacin de filas del lenguaje SQL. Es una tcnica
que permite reunir las filas de una tabla en uno o varios grupos y extraer un valor
por cada grupo. Es decir, la tabla se divide en varios grupos, cada uno de los cuales
debe tener alguna caracterstica comn, y se realizan los clculos deseados de
resumen para cada grupo.
En los ejemplos siguientes se emplearn obviamente las diversas tablas
descritas en el primer captulo. Para ilustrar algunos ejemplos de forma ms
concreta se considerar las tablas rellenadas de la siguiente forma:
Tabla PUEBLOS
Tabla FACTURAS
APRENDESQL
54
select codpue
from
pueblos;
Una sentencia select con al menos una funcin de columna devuelve una nica
lnea para toda la tabla. Por ejemplo, la siguiente sentencia cuenta el nmero total
de pueblos. En la tabla de pueblos con el contenido mostrado al principio del
captulo, el resultado es 5.
select count( *
from
pueblos;
* )
La agrupacin se indica mediante la clusula group by. Una vez agrupada una
tabla, por cada grupo slo se puede mostrar una lnea en pantalla (o, lo que es lo
mismo, una fila en el resultado final).
La anterior sentencia agrupara los pueblos del principio en grupos segn su
cdigo de provincia, es decir, se crearan tres grupos como se puede ver en la
figura siguiente:
.. LXJI)H!I.!<: .. ',, .
li<:.l~RE'''< 'G~P.BRO
101
. ---To2--..- . . . . . . .NULES
.o&ol\-
103
104
---TiYs---
SARRION
LIRIA
GA:No IA
12
12--44
46
........................................
46
AGRUPACIN
55
Una vez creados los grupos, para cada grupo se muestra lo indicado en la
clusula select, es decir, el cdigo de provincia y el nmero de filas dentro del
grupo. Por tanto, el resultado es el siguiente:
APRENDESQL
56
'yyyy' )
AGRUPACIN
57
facturas
extract( year from fecha);
Como se puede ver, los valores nulos se consideran como un valor ms, distinto
de los dems. Contando el nmero de filas dentro de cada grupo, el resultado final
sera el mostrado en la siguiente tabla:
APRENDESQL
58
* )
! Ejercicio: Escribir una sentencia que calcule la media del descuento de las
facturas para cada cliente.
Solucin: En la tabla con el contenido mostrado al principio del captulo, el
resultado se muestra en la siguiente tabla. Tras la tabla se muestra la sentencia
en SQL.
select codcli, avg( dto )
from
facturas
group by codcli;
AGRUPACIN
59
Es importante destacar que para cada grupo, la consulta devuelve una sola fila.
As pues, qu realiza la siguiente sentencia?
select codcli, avq( dto ), iva
from
facturas
qroup by codcli;
Esta sentencia es incorrecta dado que para cada cliente no existe un nico iva
sino varios (en algunas ocasiones pueden existir miles de resultados), los cuales no
caben en una nica lnea. Este es un ejemplo de consulta incorrecta que devuelve
muchos datos para cada grupo. En este caso para cada grupo nicamente puede
devolverse la caracterstica comn del grupo (codcli) o una operacin de
agrupacin (de resumen) del grupo, como por ejemplo la media del descuento, el
nmero de filas, el iva mximo, etc.
APRENDESQL
60
select
from
qroup
havinq
61
AGRUPACIN
62
APRENDESQL
* ) )
AGRUPACIN
63
5.1 O Ejercicios
: Ejercicio 5.1: Escribir una consulta que obtenga el maxtmo descuento
aplicado cada ao, considerando el descuento nulo como cero.
Ayuda: Agrupacin por una parte de la fecha.
Solucin:
select extract( year from fecha),
max( coalesce( dto, O ) )
from
facturas
group by extract( year from fecha);
APRENDESQL
64
select max( sum( cant
from
lineas_fac
qroup by codart;
precio ) )
! Ejercicio 5.5: Escribir una consulta que obtenga el cdigo de los pueblos en
los que tenemos dos o ms clientes.
Ayuda: Uso de las clusulas group by y having. Agrupacin de los clientes por
pueblos.
Solucin:
select
from
qroup
havinq
codpue
clientes
by codpue
count( * ) >= 2;
! Ejercicio 5.6: Escribir una consulta que obtenga el nmero de facturas para
cada uno de los tipos de iva (normal (iva=16), reducido (iva=7), otros), pero
slo si hay ms de 100 facturas.
Ayuda: Se debe agrupar por una expresin que devuelva un valor para el iva
16, un segundo valor para el iva 7 y un tercer valor para cualquier otro valor
del iva. Esta expresin se puede calcular con ayuda de la expresin case.
65
AGRUPACIN
Solucin:
select case iva when 16 then 1
when 7 then 2
else 3 end,
count( *
from
facturas
group by ( case iva when 16 then 1
when 7 then 2
else 3 end )
having count( * ) > 100;
l.codart
lineas_fac 1
by l.codart
max( !.precio)
= min(
!.precio);
: Ejercicio 5.8: Escribir una consulta que para cada cliente que ha hecho ms de
dos facturas durante el ao pasado, con el 16% de IVA o sin descuento,
muestre su cdigo y el nmero de facturas realizadas. Se considera que una
factura no tiene descuento si ste es cero o nulo.
Ayuda: Uso de algunas restricciones en el where y otras en el having.
Agrupacin de las facturas por cdigo de cliente.
Solucin:
select codcli, count ( * )
from
facturas
where extract ( year from fecha )
extract ( year from current_date ) - 1
( iva
and
16
or
coalesce( dto, o )
o)
group by codcli
having count(*) > 2;
: Ejercicio 5.9: Escribir una consulta que de los artculos cuyo cdigo termina
con la letra "X" (bien mayscula, bien minscula) ms un dgito numrico,
muestre el cdigo y la cantidad total pedida en las lneas de factura.
Ayuda: Uso de la funcin de agrupacin sum. Agrupacin de las lneas de
facturas por artculos.
Solucin:
APRENDESQL
66
5.11 Autoevaluacin
! Ejercicio 1: Escribir una consulta que obtenga el importe de la factura ms
alta.
! Ejercicio 2: Escribir una consulta que calcule el nmero de clientes a los que
ha realizado facturas cada uno de los vendedores de la empresa.
! Ejercicio 3: Escribir una consulta que obtenga el nmero ms alto de clientes
que viven en el mismo pueblo.
NOMJ;lRE}
. COOPR()
101
102
103
NULES
ONDA
SARRION
12
12
44
Tabla PROVINCIAS
>NOt1)R,E ' ..
12
CASTELLON
44
TERUEL
46
VALENCIA
CObl?F;()
APRENDESQL
68
select *
from
pueblos, provincias;
De todas las filas anteriores, hay algunas que resultan interesantes y otras que
no. Por ejemplo, la tercera fila no resulta interesante pues Sarrin no pertenece a la
provincia de Castelln. Las filas que interesan son las que estn relacionadas.
Como seleccionarlas? Pues con una condicin de relacin en la clusula where.
De esta forma la sentencia siguiente:
select *
from
pueblos, provincias
where pueblos.codpro = provincias.codpro;
generar las filas deseadas. stas son las filas que estn relacionadas:
69
Algunos sistemas recomiendan usar siempre los alias de tablas en todas las
columnas pues permiten al intrprete de SQL localizar la tabla de origen de las
columnas mucho antes. Pensemos en una consulta con varias tablas, cada una con
decenas de columnas. La simple bsqueda de una columna para determinar en qu
tablas aparece y si lo hace ms de una vez (posibles ambigedades) puede costar
bastante tiempo.
En algunos SGBD los alias de tablas deben definirse separando la tabla del
alias con la palabra inglesa as (adverbio de comparacin "como", en castellano).
APRENDESQL
70
71
APRENDESQL
72
73
74
APRENDESQL
select v.nombre, p.nombre
from
pueblos p join vendedores v using ( codpue )
where v.codven between lOO and 200;
! Ejercicio: Escribir una sentencia que muestre el cdigo y fecha de cada factura
junto al nombre del cliente y el nombre del vendedor de la factura.
Solucin:
select f.codfac, f.fecha, c.nombre, v.nombre
from
facturas f join clientes e using ( codcli
join vendedores v using ( codven );
75
Solucin:
select f.codfac, f.fecha, c.nombre, c.direccion,
c.codpostal, p.nombre, pr.nombre
from
facturas f join clientes e using ( codcli )
join pueblos p using ( codpue )
join provincias pr using ( codpro );
APRENDESQL
76
77
6.8 Ejercicios
! Ejercicio 6.1: Escribir una consulta que obtenga el cdigo y nombre de cada
cliente y el nmero de facturas que ha realizado durante el ao pasado.
Ayuda: Concatenacin de dos tablas y agrupacin por cdigo de cliente. Es
necesaria una agrupacin adicional por nombre de cliente.
Solucin: La siguiente sentencia se ha escrito empleando las funciones de
fecha de Oracle.
select codcli, c.nombre, count( *
from
clientes e join facturas f using ( codcli
where extract( year from f.fecha )
extract( year from current_date ) - 1
group by codcli, c.nombre;
! Ejercicio 6.2: Escribir una consulta que obtenga el cdigo de factura, la fecha
y el importe (sin considerar descuentos ni impuestos) de cada una de las
facturas.
Ayuda: Concatenacin de dos tablas y agrupacin por cdigo de factura. Es
necesaria una agrupacin adicional por fecha.
Solucin:
APRENDESQL
78
! Ejercicio 6.3: Escribir una sentencia que calcule el cdigo y nombre de cada
vendedor y su facturacin durante el ao pasado.
Ayuda: Concatenacin de tres tablas.
Solucin:
select codven, v.nombre, sum( l.cant * !.precio )
from
vendedores v join facturas f using ( codven
J01n lineas_fac 1 using ( codfac
where extract( year from f.fecha ) =
extract( year from current_date ) - 1
group by codven, v.nombre;
79
APRENDESQL
80
select codcli, c.nombre
from
pueblos p join clientes e
usinq
usinq
join facturas f
join lineas_fac 1 usinq
where p.codpro
'12'
qroup by codcli, c.nombre
havinq sum( cant * precio ) > 6000.00;
codpue
codcli
codfac
: Ejercicio 6.10: Escribir una consulta que obtenga el nombre de cada jefe y el
nmero de vendedores que dependen de l (se considerar como jefe a aquel
vendedor que es jefe de al menos otro vendedor).
Solucin:
select j.codven, j.nombre, count( *
from
vendedores j join vendedores v
en ( v.codjefe = j.codven )
qroup by j.codven, j.nombre;
6.9 Autoevaluacin
: Ejercicio 1: Para aquellos clientes de la Comunidad Valenciana cuyo nombre
comienza por la misma letra que comienza el nombre del pueblo en el que
residen, mostrar el nombre del cliente, el nombre del pueblo y el nmero de
artculos distintos comprados durante el ltimo trimestre del ao pasado. En el
listado final slo deben aparecer aquellos clientes cuya facturacin en el
mismo periodo super los 6000 euros, sin considerar impuestos ni descuentos.
: Ejercicio 2: Artculos cuya descripcin consta de ms de 15 letras o dgitos
que han sido comprados por ms de 5 clientes distintos de la provincia de
Castelln durante los ltimos diez das del ao pasado. En el listado final se
debe mostrar el artculo y su descripcin.
81
Este captulo describe en primer lugar la ordenacin del resultado obtenido por
la consulta y, en segundo lugar, las tres operaciones algebraicas que suele
proporcionar el lenguaje SQL: unin, interseccin y diferencia.
84
APRENDESQL
order
order
order
order
by
by
by
by
pr.nombre;
pr.nombre, e.nombre;
extraet( month from f.feeha ), e.eodeli;
3, 1 dese, 2 ase;
85
: Ejercicio: Facturas para el cliente con cdigo 291 o para el vendedor con
cdigo 495.
Ayuda: Se puede realizar de dos formas: con el operador union o sin l (en
este caso es ms eficiente esto ltimo).
Solucin:
select *
from
facturas
where codcli = 291
or
codven = 495;
select
from
where
un ion
select
from
where
facturas
codcli = 291
facturas
codven = 495;
86
APRENDESQL
select codpue
from
vendedores;
87
codpue
pueblos
codpue
clientes;
codpue, codpro
pueblos
nombre, codpue, codcli
clientes;
APRENDESQL
88
*
clientes
nombre like '%garcia%'
*
clientes
substr( codpostal, 1, 2)
'03';
Como se puede ver en la sentencia anterior, ambas consultas trabajan sobre las
mismas tablas. Dicha sentencia se puede rescribir muy fcilmente mediante el
operador or. Seguidamente se muestra el ejemplo anterior escrito de forma ms
eficiente:
select *
from
clientes
where nombre like '%garcia%'
or
substr( codpostal, 1, 2
'03';
7.3 Ejercicios
! Ejercicio 7.1: Escribir una consulta que obtenga el cdigo y nombre de
aquellos pueblos donde residen al menos un vendedor o al menos un cliente.
No eliminar del resultado los pueblos repetidos.
Ayuda: Operacin de unin sin eliminacin de repetidos de dos consultas. En
cada consulta se ha realizado una concatenacin con la tabla pueblos para
poder extraer el nombre del pueblo.
Solucin:
select codpue,
from
pueblos
union all
select codpue,
from
pueblos
p1.nombre
p1 join vendedores v using ( codpue )
p2.nombre
p2 join clientes e using ( codpue );
89
codpue, pl.nombre
pueblos pl join vendedores v using ( codpue )
codpue, p2.nombre
pueblos p2 join clientes e using ( codpue );
pl.nombre
pl join vendedores v using ( codpue )
p2.nombre
p2 join clientes e using ( codpue );
codpue, pl.nombre
pueblos pl join vendedores v using ( codpue )
codpue, p2.nombre
pueblos p2 join clientes e using ( codpue );
90
APRENDE SQL
from
where
! Ejercicio 7.6: Escribir una consulta que muestre el cdigo de cada artculo
cuyo stock supera las 20 unidades, con un precio superior a 15 euros, y de los
que no hay ninguna factura en el ltimo trimestre del ao pasado.
Ayuda: Uso del operador minus.
Solucin:
select
from
where
and
minus
select
from
where
and
and
a.codart
artculos a
a.stock > 20
a.precio > 15
l.codart
lineas_fac l, facturas f
f.codfac = l.codfac
to_char( f.fecha, 'q' )
'4'
extract( year from f.fecha ) =
extract( year from current_date ) - 1;
! Ejercicio 7.8: Escribir una consulta que muestre los cdigos de los artculos
tales que su stock est por debajo del doble de su stock mnimo, y el nmero
total de unidades vendidas sea mayor que 100.
Ayuda: Uso del operador intersect.
Solucin:
select a.codart
from
artculos a
where a.stock < a.stock_min
intersect
select l.codart
from
lineas_fac l
group by l.codart
having sum( l.cant ) > 100;
91
7.4 Autoevaluacin
! Ejercicio 1: Escribir una consulta que obtenga el cdigo y nombre de aquellas
provincias en las que no hubo ventas de los vendedores residentes en dichas
provincias durante el ao pasado.
Tabla PUEBLOS
94
APRENDESQL
select c.nombre cliente, p.nombre pueblo
from
clientes e, pueblos p
where c.codpue = p.codpue;
95
96
APRENDESQL
97
! Ejercicio: Escribir una consulta que devuelva el cdigo y fecha de cada factura
junto al nombre del vendedor que realiz la factura. No se debe perder ninguna
factura aunque no tenga cdigo de vendedor.
Solucin:
select f.codfac, f.fecha, v.nombre
from
facturas f left join vendedores v
using ( codven ) ;
select f.codfac, f.fecha, v.nombre
from
vendedores v right join facturas f v
using ( codven );
98
APRENDESQL
Solucin:
select l.codfac, l.linea, codart, a.descrip
from
lineas_fac 1 left join articulos a
using ( codart )
where l.codfac
100;
99
Como se puede ver, el nico cambio ha sido sustituir el operador count(*) que
devuelve 1 en el caso de Jumilla por el operador count(c.codcli) que devolver
cero en dicho caso pues el cdigo del cliente para dicho pueblo es nulo.
Como se puede ver, la primera consulta realiza una concatenacin interna, con
lo que pierde aquellos clientes cuyo cdigo de pueblo es nulo. La segunda
sentencia subsana este problema devolviendo justo aquellos clientes cuyo cdigo
de pueblo es nulo. Ntese que el nmero y tipo de las columnas de ambas
consultas deben coincidir. Por ello, la segunda consulta devuelve tambin dos
columnas.
lOO
APRENDESQL
select cl.nombre cliente, pl.nombre pueblo
from
clientes el join pueblos pl usinq ( codpue )
un ion
select NULL cliente, p2.nombre pueblo
from
pueblos p2
except
select NULL cliente, p3.nombre pueblo
from
clientes c2 join pueblos p3 usinq (codpue ));
101
8.6 Ejercicios
: Ejercicio 8.1: Escribir una consulta que muestre el cdigo y nombre de
aquellos clientes con menos de 5 facturas (incluyendo aqullos con ninguna).
Ayuda: Hay que realizar una concatenacin externa de dos tablas y una simple
agrupacin.
Solucin:
select codcli, c.nombre, count( f.codfac )
from
clientes e left join facturas f usinq ( codcli)
qroup by codcli, c.nombre
havinq count( f.codfac ) < 5;
: Ejercicio 8.2: Escribir una consulta que muestre el cdigo, descripcin y
cantidad de aquellos artculos tales que se han vendido menos de 100 unidades
(incluyendo aqullos que no se han vendido).
Ayuda: Hay que realizar una concatenacin externa de dos tablas y una simple
agrupacin. Una labor adicional es convertir el resultado del operador
sum(l.cant) al valor cero si vale nulo, principalmente en la clusula having.
Ello se debe a que en los artculos sin ventas no se cumple la condicin del
having si no se realiza previamente la conversin (pues de no hacer la
conversin se estara comparando nulo< 100, lo cual se evala a falso).
Solucin:
select codart, a.descrip, coalesce( sum( l.cant ) ' o
from
articulos a left join lineas_fac 1
usinq ( codart )
qroup by codart, a.descrip
havinq coalesce( sum( l.cant ), O) < 100;
APRENDESQL
102
Ayuda: Hay que realizar una concatenacin externa de tres tablas y una
agrupacin. Si se considera que toda provincia tiene al menos un pueblo,
bastara con una concatenacin interna y con una externa.
Solucin:
select codpro, pr.nombre, count( v.codven
from
vendedores v right join pueblos p
using ( codpue
right join provincias pr
using ( codpro
group by codpro, pr.nombre
having count( v.codven ) < 5;
! Ejercicio 8.4: Escribir una consulta que para cada factura con un importe
inferior a 3 euros, muestre su fecha, el nombre del cliente y su importe.
Ayuda: Uso de dos concatenaciones externas: la primera para que no se
pierdan facturas si no tienen cdigo de cliente asignado; la segunda para que
no se pierdan facturas si no tienen lneas.
Solucin:
select f.fecha, c.nombre,
sum( l.cant * !.precio ) importe
from
clientes e right join facturas f
using
codcli
left join lineas_fac 1
using
codfac
group by codfac, f.fecha, c.nombre
having coalesce( sum( l.cant *!.precio), O) < 3;
Ayuda: Hay que realizar una concatenacin externa de dos tablas y una
agrupacin dado que un vendedor puede no tener facturas (acaba de entrar en
la empresa) y una factura puede no tener cliente asignado en este momento.
Solucin:
select codven, v.nombre, count( codcli )
from
vendedores v left join facturas f
using ( codven )
group by codven, v.nombre
having count( f.codcli ) < 10;
103
APRENDESQL
104
8. 7 Autoevaluacin
: Ejercicio 1: Escribir una consulta que devuelva el cdigo y descripcin de.
aquellos artculos tales que el mximo descuento aplicado en sus ventas (lneas
de facturas) es menor del 10%. Se deben incluir tambin aquellos artculos
cuyo descuento es cero o nulo.
: Ejercicio 2: Escribir una consulta que obtenga el cdigo y nombre de aquellos
pueblos de Castelln donde se ha facturado a los clientes residentes menos de
1000 euros.
: Ejercicio 3: Escribir una consulta que devuelva el cdigo y nombre de
aquellos pueblos de la provincia de Castelln cuyo nmero de clientes
residentes sea menor que 5. La consulta debe devolver tambin el nmero de
clientes en cada pueblo.
9 SUBCONSULTAS
Este captulo presenta una parte de SQL muy importante: las subconsultas. Una
subconsulta no es sino una consulta que aparece dentro de otra consulta. La
posibilidad de insertar consultas dentro de otras consultas aumenta notablemente la
potencia del lenguaje SQL. Hay que decir que algunos sistemas (en realidad muy
pocos) carecen desafortunadamente de esta caracterstica.
9.1 Introduccin
Una subconsulta es una sentencia select que se utiliza dentro de otra sentencia
select. La subconsulta obtiene unos resultados intermedios (uno o ms datos) que
se emplean en la consulta principal. Las subconsultas siempre deben estar escritas
entre parntesis. Las subconsultas pueden aparecer prcticamente en cualquier
sitio de la consulta principal, aunque los lugares ms habituales son las clusulas
where y having.
Las subconsultas se pueden clasificar en los siguientes tipos, atendiendo al
nmero de filas y columnas que devuelven:
Subconsultas que devuelven un nico valor (una fila con una nica
columna).
Subconsultas que devuelven una nica fila con ms de una columna.
Subconsultas que devuelven un conjunto de filas (es decir, cero, una o varias
filas).
Seguidamente se describen con ms detalle y se presentan ejemplos de uso de
estos tres tipos de subconsultas.
APRENDESQL
106
SUBCONSULTAS
select
from
group
having
107
codcli, c.nombre
facturas f join clientes e using ( codcli
by codcli, c.nombre
count( * ) < ( select 0.5 * max( count( *
from
facturas f2
group by f2 . codcli ) ;
108
APRENDESQL
Una subconsulta que devuelve una nica fila con ms de una columna es usada
habitualmente en predicados (en el where o en el having). Su forma de uso es la
siguiente: (exprl, expr2, ...) operador ( subconsulta ). En este caso la
subconsulta debe devolver una sola fila y tantas columnas como las existentes
entre parntesis a la izquierda del operador. Es decir, el nmero de columnas a
ambos lados del operador debe coincidir. Las expresiones de la izquierda exprl,
expr2, ... se evalan y la fila que forman se compara, utilizando un operador, con la
fila que devuelve la subconsulta.
En la versin actual de la mayor parte de sistemas slo se pueden utilizar los
operadores = y <>. El predicado se evala a verdadero si el resultado de la
comparacin es verdadero para la fila devuelta por la subconsulta. En caso
contrario se evala a falso.
Si la subconsulta no devuelve ninguna fila, se evala a nulo o desconocido
(ambos trminos son sinnimos).
Hay que tener en cuenta que una restriccin, tanto en la clusula where como
en la having, se cumple si el resultado de su predicado es verdadero; si el
predicado es falso o nulo, se considera que la restriccin no se cumple.
Cuando se comparan dos filas, los atributos se comparan uno a uno segn su
posicin en la fila: el primer atributo de la primera fila con el primer atributo de la
segunda fila, el segundo atributo de la primera fila con el segundo atributo de la
segunda fila etc.
Cuando no hay ningn valor nulo en ninguno de los atributos de ambas filas,
comparar dos filas para decidir si son iguales o distintas es muy fcil: hasta un
nio podra hacerlo. Si no existen valores nulos, el resultado de una comparacin
para decidir si dos filas son iguales o distintas slo puede ser cierto o falso.
Cuando existe algn valor nulo, entonces el asunto se complica un poco ya que
el valor nulo es un valor desconocido. En este caso, el resultado de una
comparacin para decidir si dos filas son iguales o distintas puede ser cierto, falso
o desconocido (nulo).
Para decidir si dos filas son iguales o distintas se suele aplicar el mtodo
siguiente:
Dos filas se consideran iguales si todos sus atributos no son nulos y son
iguales uno a uno en ambas filas.
Si existe al menos un valor nulo en una de las filas, stas ya no pueden ser
iguales, en todo caso pueden ser distintas o se puede obtener como resultado
el valor nulo.
Dos filas se consideran distintas si al menos un atributo correspondiente de
ambas filas es distinto y con valor no nulo.
En cualquier otro caso, el resultado del predicado es nulo.
SUBCONSULTAS
109
2.
3.
4.
5.
6.
7.
8.
9. (
10.
11.
12.
13.
14.
15.
16.
6, 1
6, 1 )
6, 1
6, 5 )
( 6, null
6, 1 )
6, null ) = ( 1, null
6, null ) = ( 6, null
null, null ) = ( null, null
6, 1 ) <> ( 6, 1 )
6, 1 ) <> ( 6, 5 )
6, 1 ) <> ( 6, null
( 6, null ) <> ( 1, null
( 6, null ) <> ( 6, null
( null, null ) <> ( null, null
( null, null ) = ( subconsulta vaca )
( null, null ) <> ( subconsulta vaca
( 6, 1 ) = ( subconsulta vaca )
( 6, 1 ) <> ( subconsulta vaca )
codfac, fecha
facturas
dto = ( select max( dto
iva = ( select max( iva
from facturas
from facturas ) ;
110
APRENDESQL
111
SUBCONSULTAS
9.4.1 Operador in
En captulos anteriores se ha descrito cmo el operador in se puede emplear
para determinar si un elemento pertenece a un conjunto dado de valores. Ahora se
va a ver cmo se puede usar una subconsulta en lugar de un conjunto dado de
valores.
Este operador tiene dos formas habituales de uso: expresin in ( subconsulta )
y ( exprl, expr2,... ) in ( subconsulta ). En el primer caso el operador determina si
un valor pertenece a un conjunto de valores. En el segundo caso el operador
determina si una tupla pertenece a un conjunto de tuplas. A continuacin se
describen ambos casos con ms detalle.
Se comienza con el primer caso. El predicado expresin in ( subconsulta ) se
evala a verdadero si el resultado de la expresin es igual a alguno de los valores
de la columna devuelta por la subconsulta. El predicado se evala a falso si no se
encuentra ningn valor en la subconsulta que sea igual a la expresin. Cuando la
subconsulta no devuelve ninguna fila, tambin se evala a falso. Si el resultado de
la expresin es un nulo (la parte izquierda del operador in), el predicado se evala
a nulo. Si ninguno de los valores de la subconsulta es igual a la expresin y la
subconsulta ha devuelto algn nulo, el predicado se evala a nulo.
Al igual que ocurra en el apartado anterior, cuando no existen valores nulos,
este comportamiento es el lgico y esperable. Cuando s existen, el
comportamiento tambin es el lgico si se tiene en cuenta que el valor nulo
equivale a un valor desconocido. Por ejemplo, partiendo de este punto est claro
que la expresin 20 in ( null ) da como resultado desconocido puesto que no se
puede decir si el valor 20 est o no est en la parte derecha pues la parte derecha
tiene un valor desconocido.
10, 20, 30 )
10, 19, 30 )
10, 30, null
1 o, 20, null
subconsulta vaca
( 10, 2 o, 30 )
( 10, null, 30 )
APRENDESQL
112
select p.codpue, p.nombre
from
pueblos p
where p.codpue in ( select c.codpue
from
clientes e)
SUBCONSULTAS
113
Tabla VENDEDORES
APRENDESQL
114
115
SUBCONSULTAS
o
o
) ;
APRENDESQL
116
V amos a verlo con unos datos concretos. Supongamos la tabla de artculos que
se muestra a continuacin. La anterior sentencia ir evaluando cada artculo y lo
mostrar si su precio es mayor o igual que todos los precios de la misma tabla. En
este caso, el nico artculo cuyo precio es mayor o igual que todos los precios de
los artculos es aqul con cdigo A3.
SUBCONSULTAS
117
Tabla ARTICULOS
APRENDESQL
118
Otro aspecto en el que hay que tener mucho cuidado con este operador es ver si
la subconsulta devuelve algn resultado o no. Si la subconsulta no devuelve
ningn resultado, el operador all devuelve cierto, lo cual puede dar lugar a cierta
confusin.
a2.preco
artculos a2
a2.preco s not null
a2.codart lke 'A6%' );
Solucin: Trata de mostrar aquellos artculos cuyos precios superan a todos los
precios de los artculos cuyo cdigo comienza por A6. Pero como no hay
ningn artculo con dicho cdigo y con precio conocido, muestra todos los
artculos pues la subconsulta no devuelve ninguna fila y, por tanto, el operador
devuelve cierto.
SUBCONSULTAS
119
16% de iva.
Solucin:
select *
from
clientes e
where c.codcli = 162
and
( 16, O ) =
all ( select coalesce( f.iva, O),
coalesce( f.dto, O )
from
facturas f
where f.codcli = 162 );
APRENDE SQL
120
from
where
lineas_fac 1
l.codfac = f.codfac );
Solucin: Obtiene los datos de las facturas que tienen descuento en todas sus
lneas:
En este caso existe una referencia externa y sta es f.codfac ya que hace
referencia a una columna de la consulta principal. Se puede suponer que la
consulta se ejecuta del siguiente modo. Se recorre, fila a fila, la tabla de facturas.
Para cada fila se ejecuta la subconsulta, sustituyendo f.codfac por el valor que
tiene en la fila actual de la consulta principal. Es decir, para cada factura se
obtiene el descuento mnimo en sus lneas. Si este descuento mnimo es mayor que
cero, significa que la factura tiene descuento en todas sus lneas, por lo que se
muestra en el resultado. Si no es as, la factura no se muestra. En cualquiera de los
dos casos, se contina procesando la siguiente factura: se obtienen sus lneas y el
descuento mnimo en ellas, etc.
! Ejercicio: Escribir una sentencia que muestre el nmero de clientes a los que
en sus facturas siempre se les ha aplicado un iva del 16 % y sin descuento.
Solucin:
select count( * )
from
clientes e
where
( 16, O) = all ( select coalesce( iva, O),
coalesce( dto, O )
from
facturas f
where f.codcli = c.codcli );
121
SUBCONSULTAS
APRENDESQL
122
Solucin:
select p.codpue, p.nombre
from
pueblos p
where not exists( select '*'
from
clientes e
where c.codpue = p.codpue );
Solucin:
select v.codven, v.nombre
from
vendedores v
where not exists( select *
from
facturas f
where f.iva = 16
and
f.codven = v.codven );
as ivat,
SUBCONSULTAS
123
from
* ) )
! Ejercicio: Escribir una consulta (con una subconsulta en la clusula from) que
devuelva el mayor descuento medio aplicado en las facturas de un cliente.
Solucin:
select max( dto_med )
from
( select avg( dto ) as dto_med
from
facturas
group by codcli );
! Ejercicio: Escribir una consulta que obtenga el cdigo de las facturas en las
que se ha comprado el artculo que actualmente es el ms caro. Escribir en
primer lugar una sentencia habitual que use subconsultas en la clusula where
y en segundo, una sentencia que use subconsultas en la clusula from.
Solucin:
APRENDESQL
124
SUBCONSULTAS
125
APRENDESQL
126
Solucin: No. La consulta anterior muestra aquellos artculos que alguna vez
(en alguna factura) se han vendido en cantidad superior a 5 unidades.
As pues, la solucin anterior no sirve. Para resolver este problema se puede
aplicar el mtodo de la doble negacin: un artculo se habr vendido siempre en
cantidades superiores a 5 unidades si se ha vendido alguna vez y nunca se ha
vendido en cantidades inferiores o iguales a 5 unidades. La siguiente sentencia
obtiene el resultado deseado:
se1ect a.codart, a.descrip
from
articu1os a
where a.codart -in ( se1ect 1.codart
from
1ineas_fac 1 )
and
not exists( se1ect '*'
from
1ineas_fac 1
where 1.codart = a.codart
and
1.cant <= 5 );
a.codart, a.descrip
1ineas_fac 1 join articu1os a usinq ( codart
a.codart, a.descrip
1ineas_fac 1 join articu1os a usinq ( codart )
1.cant <= 5;
codart, a.descrip
1ineas_fac 1 join articu1os a usinq ( codart
by codart, a.descrip
min( 1.cant ) > 5;
SUBCONSULTAS
127
9.1 O Ejercicios
! Ejercicio 9.1: Escribir una consulta que muestre el nmero de artculos con un
precio superior al 55% del precio mximo de los artculos.
APRENDESQL
128
! Ejercicio 9.2: Escribir una consulta que muestre el nombre de la provincia con
mayor nmero de clientes.
Ayuda: La subconsulta debe calcular el nmero mximo de clientes de una
provincia.
Solucin:
select pr.nombre
from
provincias pr join pueblos p using
codpro
J01n clientes e using
codpue
group by codpro, pr.nombre
having count( * )
( select max( count( * ) )
from
pueblos p2 join clientes c2
using ( codpue
group by p2.codpro );
SUBCONSULTAS
129
! Ejercicio 9.5: Escribir una consulta que muestre el cdigo y fecha de las
facturas con descuento para aquellos clientes cuyo cdigo postal comienza por
12.
Ayuda: La subconsulta obtiene los cdigos de clientes cuyo cdigo postal
comienza por 12. La consulta principal muestra aquellos clientes cuyo cdigo
se encuentra entre los encontrados. La consulta y la subconsulta se unen con el
operador in o con el= any.
Solucin:
select
from
where
and
f.codfac, f.fecha
facturas f
coalesce( f.dto, O
f.codcli in ( select
from
where
> o
c.codcli
clientes e
c.codpostal like '12%' );
! Ejercicio 9.6: Escribir una consulta que muestre el nmero de pueblos en los
que no tenemos clientes.
Ayuda: Uso de una subconsulta con negacin.
Solucin:
select count( * )
from
pueblos
where codpue not in
se1ect codpue
from
clientes);
! Ejercicio 9.8: Escribir una consulta que muestre el nmero de artculos cuyo
stock supera las 20 unidades, con un precio superior a 15 euros y de los que no
hay ninguna factura en el ltimo trimestre del ao pasado.
Ayuda: Uso de una subconsulta (con o sin referencia externa) con negacin
simple.
Solucin:
select
from
where
and
and
count( * )
articulos a
a.stock > 20
a.precio > 15
a.codart not in
( select l.codart
APRENDESQL
130
frem
where
and
select
frem
where
and
and
ceunt( * )
articules a
a.steck > 20
a.precie > 15
net exists(
select '*'
lineas_fac 1 jein facturas f
frem
using
cedfac )
where te_char( f.fecha, 'q' )
'4'
and
extract( year frem f.fecha ) =
extract( year frem current_date ) - 1
and
l.cedart = a.cedart );
cedart, a.descrip
lineas_fac 1 jein articules a using ( cedart )
cedart, a.descrip
facturas f jein lineas_fac 1 using ( cedfac )
131
SUBCONSULTAS
where
codfac
codart
<= 3;
a.codart, a.descrip
articulos a
a.precio > 90.15
10 >
( select coalesce( sum( cant ), O)
from
lineas_fac 1 join facturas f
using
codfac
where extract( year from f.fecha )
extract( year from current_date ) - 1
and
l.codart = a.codart );
=(
Ejercicio 9.12: Escribir una consulta que muestre el nombre del cliente con
mayor facturacin.
APRENDESQL
132
SUBCONSULTAS
133
! Ejercicio 9.16: Escribir una consulta que obtenga el cdigo y nombre de los
clientes cuyas facturas han sido siempre inferiores a 1000 euros.
Ayuda: Operacin del tipo todo: se puede resolver con minus o con doble
negacin.
Solucin:
select codcli, c.nombre
from
clientes e join facturas f
using
join lineas_fac 1 using
group by codcli, c.nombre
having sum( l.cant * l.precio ) < 1000.00
minus
select codcli, c.nombre
from
clientes e join facturas f
using
join lineas_fac 1 using
group by codcli, c.nombre
having sum( l.cant * !.precio ) >= 1000.00;
codcli
codfac
codcli
codfac
9.11 Autoevaluacin
! Ejercicio 1: Cdigo y nombre de aquellos clientes de Castelln que durante el
ao pasado siempre han comprado artculos cuyo precio iguala o supera los 20
euros. Resolver el ejercicio de dos formas distintas.
134
APRENDESQL
[null
not null]
donde se observa que resulta obligatorio especificar el nombre, que debe ser nico
en la tabla, y el tipo, mientras que es opcional indicar si acepta nulos o no y si va a
tener un valor por defecto cuando se realice una insercin de una fila. Realmente si
no se especifica lo contrario el campo aceptar nulos y el valor por defecto ser
nulo. Por lo que respecta a los tipos, se muestran seguidamente los ms comunes:
character (dim) hace referencia a una cadena de caracteres de dimensin
mxima igual a dim. En Oracle tambin se acepta el tipo varchar2 (dim).
APRENDESQL
136
boolean es un campo cuyos nicos valores vlidos son true o false. Oracle
no dispone de este tipo de datos.
date es un campo en donde se almacena una fecha.
time es un campo en donde se almacena una hora de un da.
numeric es un campo que almacena nmeros enteros de como mximo dim
dgitos. En Oracle tambin se utiliza el tipo number (dim).
decimal (dim, tam) es un campo que almacena nmeros reales de hasta dim
dgitos y como mucho tam dgitos decimales. En Oracle resulta ms comn
la utilizacin del tipo number (dim, tam).
A continuacin se muestran un par de ejemplos de creacin de tablas en las que
nicamente se incluyen la definicin de los campos.
: Ejercicio: Creacin de la tabla de provincias, sin restricciones.
Solucin:
create table provincias (
codpro character(2) not null,
nombre character(20) not null default '
');
Las restricciones son los elementos del modelo relacional que permiten que ste
funcione, ya que sin ellas una base de datos no es ms que un mero almacn de
informacin pero sin ningn tipo de conexin entre los datos. La definicin de
stas presenta una misma estructura:
constraint nombre tipo parametros
Es importante destacar que el nombre definido para una restriccin debe ser
nico para toda la base de datos, por lo que se aconseja tomar un criterio general
que incluya el tipo de restriccin, la tabla o tablas que involucra, y los campos
correspondientes. En los ejemplos posteriores se utilizar un criterio posible.
Seguidamente se muestra para los diferentes tipos de restricciones el valor de tipo
y parametros.
Definicin de la clave primaria de una tabla.
primary key (campol[, campo2, ... 1 )
Definicin de una clave alternativa de una tabla.
unique (campol[, campo2, ... 1 )
Definicin de la clave ajena de una tabla sobre otra.
137
] )]
APRENDESQL
138
restrict, si existe alguna fila que tiene como clave ajena el valor de la
clave primaria que se desea borrar en la tabla referida, la fila asociada
no se borra.
La clusula on update quiere indicar que ocurrir cuando se intente
modificar en la tabla referida la fila a la que apunta una fila de la tabla
actual. Se definen las mismas cinco opciones que antes.
no action, es decir, no hacer nada, pero modificar la fila en la tabla
referida, lo que puede provocar problemas de falta de integridad de los
datos.
set null, se asigna el valor null en los campos que forman la clave
ajena de aquellas filas que tengan como clave ajena el valor de la clave
primaria que se desea modificar en la tabla referida, y posteriormente
se modifica esta fila.
set default se asigna el valor por defecto en los campos que forman la
clave ajena de aquellas filas que tengan como clave ajena el valor de la
clave primaria que se desea modificar en la tabla referida, y
posteriormente se modifica esta fila.
cascade, se modifican las filas que tienen como clave ajena el valor de
la clave primaria que se desea modificar en la tabla referida antes de
modificar stas.
restrict, si existe alguna fila que tenga como clave ajena el valor de la
clave primaria que se desea modificar en la tabla referida, la fila
asociada no se modifica.
Ahora se presentan los ejemplos comentados con anterioridad pero en los que
ya se detallan las restricciones de cada tabla.
not null,
not null,
not null default 0.0,
primary key ( codart ),
139
constraint ch_precio_articulos
check (precio> 0.0 ),
constraint ch_strockm_articulos
check ( coalesce( stock_min, O
>O),
constraint ch_stock_articulos
check ( coalesce( stock, O) >O
);
Obviamente no se puede borrar una tabla en cualquier momento, sino que slo
se podr borrar si no existe ninguna otra tabla en la base de datos que la referencia,
por lo que la eliminacin de las tablas de una base de datos se debe realizar en un
orden determinado. Es por ello que no es posible borrar la tabla artculos si no se
ha borrado previamente la tabla lineas_fac.
APRENDESQL
140
Solucin2:
insert into articules
( codart, descrip, precio, stock, stock_min )
values ( 'ARTXXX', 'Articulo de prueba 1', 10.20,
90, 10 ) ;
Como se puede observar, esta operacin requiere que se indique la tabla sobre
la que se desea realizar la insercin de los datos y los valores que se desean
insertar, pero no es necesario indicar las columnas sobre las que se desea realizar
la operacin. Esta situacin es vlida pero debe ajustarse a una serie de
condiciones,
l. Todo valor especificado dentro de la clusula values se debe corresponder
en tipo y dimensin con la columna que aparece en el mismo lugar, es
decir, el valorl con la columnal, el valor2 con la columna2, ... El valor
null es uno de los valores vlidos que se puede especificar para cualquier
tipo de columna.
2. Si en la definicin de la tabla aparecen ms columnas que las especificadas
en la operacin, el resto de columnas de la fila introducida toman su valor
por defecto, si lo tuviera, o bien null.
3. Si no se especifican las columnas de la tabla, se asume el orden de las
columnas especificado en su creacin, pudindose especificar menos
valores que columnas tenga la tabla.
4. En cualquiera de los casos se debe asegurar que el valor de la clave
primaria introducida sea no nula y nica, que los valores no nulos
introducidos en las claves ajenas existen en la tabla referida, y que se
cumplen el resto de caractersticas de los atributos.
141
Solucin2:
insert into articules ( codart, descrip, precio,
stock, stock_min )
values
'ARTYYY', 'Artculo de prueba 2', 10.20,
NOLL, 10 )
Solucin3:
insert into articules ( codart, descrip, precio,
stock_,min)
values ( 'ARTYYY', 'Artculo de prueba 2', 10.20,
10 ) ;
Solucin2:
insert into articules ( codart, descrip, precio
values ( 'ARTZZZ', 'Artculo de prueba 3', 10.20 );
... ) ]
APRENDESQL
142
... ]
2;
143
Tabla ARTICULOS
1.1;
Tabla ARTICULOS
Modificada
Solucin:
update artculos
set precio =precio * 0.9,
stock_min = stock_min * 1.25
where codart in
( select l.codart
from
lineas- fac 1 join facturas f
usinq ( codfac
where extract( year from fecha ) =
1
extract ( year from sysdate )
qroup by l.codart
havinq sum( l.cant * !.precio ) < 100 ) ;
APRENDESQL
144
En este caso hay que tener en cuenta que no todas las filas podrn ser borradas,
sino que se borrarn nicamente aquellas que cumplan las restricciones existentes
en la base de datos por la definicin de las claves ajenas.
APRENDESQL
146
147
! Ejercicio: Creacin de una vista que muestre nicamente los cdigos postales
de los clientes de la provincia de Castelln.
Solucin:
create view codigos_clientes as
select distinct codpostal
from
clientes
where codpostal like '12%';
APRENDESQL
148
Una vez defmidas, las vistas pueden ser utilizadas en las sentencias select,
exactamente igual a como se realizara con una tabla de la base de datos, tal y
como se muestra en los ejercicios siguientes:
: Ejercicio: Seleccin de los clientes de Castelln de los que tenemos
informacin sobre su cdigo postal.
Solucin:
select c.nombre, c.direccion
from
clientes e join codigos_clientes
using ( codpostal );
=(
'46' ) ) ;
149
150
APRENDESQL
151
Crear un ndice sobre las claves ajenas que se utilicen con frecuencia para
hacer concatenaciones mediante JOIN.
Crear un ndice sobre los atributos que se utilizan con frecuencia para hacer
restricciones WHERE (son condiciones de bsqueda).
Crear un ndice nico sobre las claves alternativas que se utilizan para hacer
bsquedas. Al igual que ocurre con las claves primarias, los SGBD suelen
mantener la unicidad de las claves alternativas mediante un ndice nico que
crean automticamente.
Evitar los ndices sobre atributos que se modifican a menudo.
Evitar los ndices sobre atributos poco selectivos, aquellos en los que la
consulta selecciona una porcin significativa de la tabla (ms del 15% de las
filas).
Evitar los ndices sobre atributos formados por tiras de caracteres largas.
Evitar los ndices sobre tablas que se actualizan mucho y que se consultan
muy espordicamente (tablas de auditora o diarios). Si se han creado
ndices sobre este tipo de tablas, podra ser aconsejable eliminarlos.
Revisar si hay ndices redundantes o que se solapan y eliminar los que no
sean necesarios.
Seguidamente se presentan dos ejemplos de creacin de ndices, ambos
asociados a una clave primaria, pero en uno de ellos se obliga a definir un orden
determinado en el almacenamiento de la informacin.
APRENDESQL
154
Solucin:
select distinct codart
from
lineas_fac
where codfac < 100;
codpue, nombre
pueblos
codpro = '12'
upper( substr( nombre, 1, 1 ) ) =
upper( substr( nombre, length( nombre), 1) );
155
and
precio ) )
APRENDESQL
156
! Ejercicio 2: Escribir una consulta que calcule el nmero de clientes a los que
han realizado facturas los vendedores de la empresa.
Solucin:
select codven, count( distinct codcli
from
facturas
group by codven;
* )
157
Castelln durante los ltimos diez das del ao pasado. En el listado final se
debe mostrar el artculo y su descripcin.
Solucin:
select codart, a.descrip
from
artculos a join lineas_fac 1 using
join facturas f
using
join clientes e
using
J01n pueblos p
using
where length( a.descrip ) > 15
1 12 1
and
p. codpro
and
extract( year from f.fecha ) =
extract( year from current_date ) - 1
and
extract( month from f.fecha )
12
extract( day from f.fecha ) > 21
and
group by codart, a.descrip
having count( distinct codcli ) > S;
codart
codfac
codcli
codpue
codpro
codpue
codcli
codfac
APRENDESQL
158
where
and
and
and
or
and
group
on ( v.codpue=p1.codpue
join facturas f using ( codven
join clientes e using ( codcli
join pueblos p2
on ( c.codpue=p2.codpue
extract( year from f.fecha ) =
extract( year from current_date ) - 1
extract( month from f.fecha ) = 12
extract( day from f.fecha ) > 21
( upper( v.nombre ) like '%EZ %'
upper( v.nombre ) like '%EZ' )
p1.codpro = p2.codpro
by codven, v.nombre;
where
codpro, pr.nombre
provincias pr
codpro, pr.nombre
provincias pr join pueblos p
using ( codpro
join vendedores v
using ( codpue
join facturas f
using ( codven
extract( year from f.fecha ) =
extract( year from current_date ) - 1;
codart, a.descrip
articulas a join lineas_fac 1 using ( codart )
codart, a.descrip
articulas a join lineas_fac 1 using ( codart
join facturas f using ( codfac )
159
where
p.codpro
codcli
codpue
codpro
codpue
codcli
1 );
APRENDESQL
160
161
minus
select codcli, c.nombre
from
clientes e join pueblos p
using
codpue
join facturas f
using
codcli
join lineas_fac 1 using
codfac
where extract ( year from f.fecha )
extract ( year from current_date )
1
and
p.codpro
'12'
!.precio < 20.00;
and
select
from
where
and
codcli, c.nombre
clientes e join pueblos p
using ( codpue )
p.codpro
'12'
codcli in
( select f.codcli
from
facturas f join lineas_fac 1
using ( codfac
where extract( year from f.fecha )
extract ( year from current_date ) -1
codcli not in
( select f.codcli
from
facturas f join lineas_fac 1
using ( codfac
where extract ( year from f.fecha )
extract( year from current_date ) -1
and
!.precio < 20.00
and
f.codcli is not null ) ;
and
APRENDESQL
162
Solucin:
select codven, v1.nombre
from
vendedores v1 join facturas f1 using
join lineas_fac 11 using
where extract( year from f1.fecha )
extract( year from current_date ) - 1
group by codfac, codven, v1.nombre
having count( distinct 11.codart ) > 5
minus
select codven, v2.nombre
from
vendedores v2 join facturas f2 using
join lineas_fac 12 using
where extract( year from f2.fecha )
extract( year from current_date ) - 1
group by codfac, codven, v2.nombre
having count( distinct 12.codart ) <= 5;
codven )
(codfac)
codven )
(codfac)
from
where
and
group
163
13 EJERCICIOS AVANZADOS
APRENDESQL
166
from
where
and
order
by 2;
codart, a.descrip
articulos a
codart, a.descrip
articulos a join lineas_fac 1 using(
join facturas f
using(
join clientes e
using(
J01n pueblos p
using(
where p.codpro in ( '03', '12', '46' )
group by codart, a.descrip
having sum( l.cant ) >= 10
order by 2;
codart
codfac
codcli
codpue
EJERCICIOS A V ANZADOS
order
167
join lineas_fac 1
using( codfac
to_number( to_char( f.fecha, 'd' )
<= 2
and
order
by 2;
APRENDESQL
168
select
from
minus
select
from
v.codven, v.nombre
vendedores v
codven, v.nombre
vendedores v join facturas f
using( codven
join lineas_fac 1 using( codfac
group by codven, v.nombre
having sum( !.precio * l.cant ) >= 1000.00
order by 2;
EJERCICIOS AVANZADOS
169
)=
APRENDESQL
170
group
order
select codfac
from
facturas f2 join lineas_fac 1
using( codfac
group by codfac
having sum( !.precio * l.cant ) > 250 )
by codcli, c.nombre
by 2;
count( count( * ) )
clientes e join facturas f using( codcli
by c.codpue
count( * ) > 250;
EJERCICIOS AVANZADOS
171
APRENDESQL
172
EJERCICIOS A VANZADOS
qroup
order
173
: Ejercicio 17: Para todas las provincias con ms de 500 pueblos, incluidas las
que no tuvieron ninguna venta, mostrar su cdigo, su nombre y el nmero total
de unidades vendidas de artculos por parte de los vendedores de la provincia,
todo ello ordenado respecto del cdigo de provincia.
Solucin:
select codpro, pr.nombre, sum( l.cant ) Total
from
provincias pr join pueblos p
usinq( codpro
left join vendedores v usinq( codpue
left join facturas f
usinq( codven
left join lineas fac 1 usinq( codfac
qroup by codpro, pr.nombre
havinq count( distinct codpue ) > 500
order by 1;
=
=
and
v1.codven not in (
select codven
from
vendedores v3 join facturas f3
usinq( codven )
where extract( day from f3.fecha ) > 20
)
order by 2;
Solucin: Cdigo y nombre de los vendedores que siempre realizan sus ventas
en los primeros 20 das de cada mes y cuyo jefe no es de la provincia de
Castelln.
APRENDESQL
174
codcli
codfac
1
codcli
codfac
1
175
EJERCICIOS A V ANZADOS
by 2;
176
APRENDESQL
extract( year from current_date ) - 1
group by 12.codart )
order by 2;
codart, a.descrip
articules a join lineas_fac 1 using( codart )
by codart, a.descrip
max( coalesce( l.dto, O ) )
O
by 2;
codcli, c.nombre
clientes e join pueblos p using( codpue )
p.codpro
'12'
2 <
select count( distinct p2.codpro )
from
pueblos p2 join vendedores v
using( codpue
join facturas f
using( codven
EJERCICIOS AV ANZADOS
order
where f.codcli
by 2;
177
= c.codcli
APRENDESQL
178
usinq
codfac )
extract( year from f.fecha ) =
extract( year from current_date ) - 1
qroup by codfac, f.codcli
havinq sum( 1.cant ) <= SO
where
order by 1;
! Ejercicio 29: Para todos los clientes de la base de datos que tengan menos de
1O facturas, mostrar su cdigo, nombre, y nmero total de unidades que han
comprado de los artculos cuyo stock actual est por debajo de las 50 unidades.
Cuando un cliente no tiene facturas el nmero de unidades mostradas debe ser
cero.
Solucin:
se1ect codc1i, c.nombre,
sum( case when coa1esce( a.stock, O ) < SO
then coalesce( l.cant, O )
EJERCICIOS A V ANZADOS
179
180
APRENDESQL
where
and
order
join pueblos p2
p2.codpro
'12'
12.cant <= S
by 2, 1;
using( codpue )
)
)
)
)
a.codart, a.descrip
artculos a
upper( a.descrip ) like '_A%'
10 <
( select count( distinct f.codcli
from
facturas f join lineas_fac 1
using( codfac )
where extract ( month from f.fecha ) > 6
and
extract( year from f.fecha )
extract ( year from current_date
- 1
l.codart
a.codart )
and
by 2, 1;
order
EJERCICIOS A V ANZADOS
Ul
Solucin: Para cada artculo que se haya vendido alguna vez y que todas las
veces que se vende es con un precio inferior a su precio actual, mostrar su
cdigo y el nmero de lneas de pedido de ese artculo donde la cantidad es
superior a la media.
! Ejercicio 34: Mostrar, ordenadamente, el cdigo y el nombre de los
vendedores que siempre venden a clientes de su misma provincia. Considerar
solamente los vendedores que tengan facturas.
Solucin:
select v.codven, v.nombre
from
vendedores v
where not exists(
select *
from
facturas f join clientes e
usinq( codcli
join pueblos pl
usinq( codpue )
cross join pueblos p2
where f.codven= v.codven
v.codpue = p2.codpue
and
and
pl.codpro <> p2.codpro
and
exists(
select *
from
facturas f
where f.codven= v.codven
order by 2, 1;
APRENDESQL
182
select
from
minus
select
from
codven, v.nombre
vendedores v join facturas f using( codven )
codven, v1.nombre
vendedores v1 join facturas f1 using( codven
join clientes c2 using( codcli
join pueblos p1
on (v1.codpue
p1.codpue)
join pueblos p2
on (c2.codpue = p2.codpue)
p1.codpro <> p2.codpro
by 2, 1;
where
order
: Ejercicio 35: Recuperar las facturas con mayor importe total. Para cada
factura mostrar su cdigo, el cdigo del cliente, el cdigo del vendedor, su
importe total, y el nmero de artculos diferentes que contiene en sus lneas.
Solucin:
select codfac, f1.codcli, f1.codven,
sum( 11. cant * 11.precio ) ,
count( distinct 11.codart )
from
facturas f1 join lineas_fac 11 using( codfac )
group by codfac, f1.codcli, f1.codven
having sum( 11.cant * 11.precio ) =
( select max( sum( 12.cant * 12.precio ) )
from
facturas f2 join lineas_fac 12
using( codfac )
group by codfac )
order by 1;
14 ANEXOS
184
APRENDESQL
185
BIBLIOGRAFA
188
APRENDESQL
"SQL for Smarties. Advanced SQL Programming".
Joe Celko.
Morgan Kaufmann Publishers, 1999.
"Gua LAN Times de SQL".
James R. Groff, Paul N. Weinberg.
Osbome McGraw-Hill, 1998.
"SQL El lenguaje de las bases de datos relacionales. Gua de referencia
rpida".
John Viescas.
Microsoft Press, Anaya Multimedia, 1991.
"Aplique SQL".
James R. Groff, Paul N. Weinberg.
Osbome/McGraw-Hill, 1991.