Manual SQL Parte 2
Manual SQL Parte 2
Funciones de agregacin
Las funciones de agregacin son funciones que toman una coleccin de valores como entrada
y producen un nico valor como salida. Aunque SQL ANSI tiene bastantes funciones de este
tipo, las de uso bsico podemos concentrarlas en 5 (Access no ofrece todas las de SQL ANSI)
que son avg(media), min(mnimo), max (mximo), sum (total) y count (cuenta).
La entrada de las funciones sum y avg debe ser una coleccin de nmero, pero le resto de
funciones pueden operar sobre colecciones de datos de cualquier tipo. Por ejemplo:
select avg([gastos de envo])
from pedidos
where [id de cliente] >=10
nos dar la media de los gastos de envo de la tabla pedidos para todos aquellos cliente con id
mayor o igual que 10, opcionalmente podramos haber usado el renombramiento con la
partcula as para dar un nombre al atributo calculado y que no ponga el motor de base de
datos uno propio (en caso de Access del tipo Expr1).
Hay veces en las que es deseable aplicar la funcin de agregacin no slo a un nico conjunto
de tuplas (como el ejemplo anterior), sino tambin a un grupo de conjuntos de tuplas, esto lo
conseguimos en SQL usando la clusula group by. El atributo o atributos especificados en la
clusula group by se usa para formar los grupos sobre los que vamos a operar. Las tuplas con
el mismo valor en todos los atributos especificados en el group by se colocan en el mismo
grupo. Por ejemplo podra interesarnos saber la media de los gastos de envi pero por cliente,
eso lo formularemos de la siguiente forma:
select [id de cliente], avg([gastos de envo])
from pedidos
group by [id de cliente]
Hay que tener en cuenta que cuando utilicemos funciones de agregacin los campos que
usemos en el select sin ser funciones de agregacin tendrn que estar obligatoriamente dentro
del group by como es lgico, as la siguiente construccin nos dar un error:
select [id de cliente], avg([gastos de envo])
from pedidos
A veces comprobaremos que es ms til establecer una condicin que se aplique a los grupos
que una que apliquemos a las tuplas. Por ejemplo si en las anteriores select queremos saber
slo aquellos conjuntos donde la media de los gastos es mayor que 50, esta condicin dado
que es relativa a una funcin de agregacin no se podra poner en el where (condiciones para
registros) sino que habra que ponerla en la clusula having (condiciones para conjuntos), y
nos quedara:
En este caso vemos como adems hemos usado el renombramiento para obtener el atributo
gastos con el valor de la media y en el having introducimos la condicin buscada (en el
having no podemos usar alias sino la propia funcin de agregacin.
Como hemos denotado antes si no ponemos clusula group by se est haciendo la agrupacin
para todo el conjunto de la relacin sin separar por grupos. La funcin count se suele usar para
calcular el nmero de registros de una relacin entera simplemente escribiendo:
Select count(*)
From pedidos
Esta sentencia primero buscara aquellas tuplas cuyo id cliente sea mayor que 10, con todos los
registros devueltos se formarn los grupos por id de cliente y se hallar la media de los gastos
de envo y de estos grupos se eliminarn aquellos que no cumplan la condicin de que la
media sea mayor que 50.
Adems de estas funciones que hemos visto de agregacin Access ofrece First, Last (que
devuelven el primer y ltimo registro devuelto en el conjunto), StDev, StDevP, Var y VarP para
calcular Desviaciones tpicas y varianzas.
Valores nulos
SQL permite el uso de valores nulos para indicar la ausencia de informacin sobre el valor de
un atributo. En Access al igual que en otras bases de datos hay que diferenciar entre el valor
Nulo y la cadena vaca, lo que en ingls se llama ZLS (Zero Length String). La diferencia esencial
es que mientras que el valor Nulo nos indica que el atributo no tiene valor (al menos todava)
el ZLS nos indica que el atributo tiene el valor de vaco (blank en la terminologa de base de
datos).
SQL nos permite usar en las condiciones la palabra clave null para consultar este tipo de
valores. De esta forma la siguiente consulta:
select *
from clientes
where correo is null;
Nos devolver todas las tuplas de la relacin clientes en la que el correo sea nulo, es decir no
tenga ningn valor. En cambio la consulta:
select *
from clientes
where correo="";
Nos devolver aquellas tuplas que en el atributo correo tengan un valor de vaco (que es un
valor, no como Nulo que no es ningn valor.
Tambin podemos utilizar la negacin de forma que el predicado is not null preguntar por la
ausencia de valor nulo.
El uso del valor nulo en las operaciones matemticas y de comparacin puede darnos muchos
quebraderos de cabeza. El resultado de las operaciones aritmticas es nulo si cualquiera de los
valores de entrada es nulo, de forma que si sumamos una columna con otra y en una de ellas
alguno de los valores es nulo el resultado para esa fila del resultado ser nulo, es decir si
sumamos 200 + Nulo = Nulo. El resultado de cualquier comparacin que involucre a un Nulo se
considera de facto falso, aunque el SQL ANSI habla de que el resultado de estas comparaciones
tendra que ser Desconocido, en la prctica se convierte en falso. De este modo si comparamos
dos columnas con nmeros y en una de ellas hay nulos, la comparacin de la primera > que la
segunda nos dara falso en aquellas que haya un nulo, quedando cosas como que 200>Nulo =
False.
Tambin hay que tener cuidado con los valores nulos en las funciones de agregacin, el
estndar SQL dice que los nulos deben ser ignorados por todas las funciones de agregacin
excepto por la funcin Count.
Subconsultas anidadas
SQL proporciona mecanismos para las subconsultas anidadas. Una subconsulta es una
expresin select-from-where que se anida dentro de otra consulta. Un uso comn de las
subconsultas es llevar a cabo comprobaciones sobre pertenencia a conjuntos, comparacin de
conjuntos o cardinalidad de conjuntos.
Para la pertenencia a conjuntos se usa la conectiva in que comprueba la pertenencia a un
conjunto, donde el conjunto es la coleccin de valores resultado de una clusula select. La
conectiva not in comprueba la no pertenencia. Por ejemplo:
SELECT *
from clientes
where id in (select [id de cliente]
from pedidos);
con esta sentencia estaramos buscando todos los datos de los clientes que tienen pedidos,
fijaros que la condicin lo que nos dice en lenguaje natural algo como: cuyo identificativo este
entre los identificativos de cliente de la relacin pedidos. Est misma consulta la podramos
hacer mediante unin de tablas de la siguiente forma:
SELECT distinct clientes.*
from clientes,pedidos
where clientes.id=pedidos.[id de cliente];
En este caso usamos el distinct para que no nos duplique todos los registros devueltos por la
consulta. Otra forma de hacerlo sera con los joins entre las relaciones como se ver
posteriormente. La bsqueda contraria es decir dime todos los clientes que no tengan pedidos
es muy fcil pensarla de forma de consulta anidada pues en lenguaje natural sera Dime todos
los clientes que no estn en la tabla de pedidos lo cual pasado a SQL quedara:
SELECT *
from clientes
where id not in (select [id de cliente]
from pedidos);
Est consulta realizada sin subconsulta no es tan sencilla de realizar y a veces es imposible.
Aunque SQL ANSI permite subconsultas sobre varios campos, en Access la subconsulta siempre
est limitada a un solo atributo. Hay que tener en cuenta que los operadores in y not in
tambin pueden ser usados sobre enumeraciones, de la siguiente forma:
select *
from pedidos
where [id de cliente] in (1,2,3);
De esta forma podramos obtener todos los pedidos que haya solicitados los clientes con
identificativo 1,2 o 3.
SQL ofrece una serie de herramientas para la comparacin de conjuntos, por ejemplo si
imaginamos una tabla de sucursales bancarias con un campo de ciudad de la sucursal y otro de
activo que posee dicha sucursal podramos hacer consultas como consultar por todas las
sucursales que tengan ms activo que alguna de las sucursales sitas en Barcelona se podra
hacer con:
Select nombresucursal
From sucursales
Where activo > some (select activo
From sucursales
Where ciudad=Barcelona)
La subconsulta en este caso crea un conjunto con los valores de activo de todas las sucursales
sitas en Barcelona y la comparacin > some ser cierta si el valor del atributo activo en la
tupla seleccionada por la select externa es mayor que alguno de los valores recuperados por la
select interna. Otras comparaciones con some son < some, <= some, >= some, = some y <>
some. Se puede comprobar que =some es idntico a usar el in pero tener en cuenta que
<>some no es lo mismo que not in. En lugar de some se puede usar la palabra any.
Otra construccin parecida a some es la de all, se hace de la misma forma pero en este caso
comprueba contra todas las filas devueltas por la consulta anidada. De forma que:
Select nombresucursal
From sucursales
Where activo > all (select activo
From sucursales
Where ciudad=Barcelona)
Devolvera todas aquellas sucursales cuyo activo fuera extrictamente mayor que el de
cualquier sucursal de Barcelona (es decir superior a todas ellas), tiene las mismas distintas
construcciones que el some, y se puede comprobar que <>all es equivalente al not in.
Cuando queremos comparar funciones de agregacin tambin son tiles pues no podemos
agregar de forma fcil funciones de agregacin, por ejemplo para saber el cliente que ha hecho
el mximo gasto en la tabla pedidos en gastos de envo podramos utilizar:
select [id de cliente]
from Pedidos
group by [id de cliente]
having avg([gastos de envo])>=all (select avg([gastos de envo])
from Pedidos
group by [id de cliente])
Con la palabra clave exists podemos hacer comprobacin de relaciones vacas comprobando si
una subconsulta no produce ninguna tupla como resultado, devolviendo un valor true si la
subconsulta argumento no es vaca. De esta forma tambin podemos preguntar dime los
clientes que tienen pedidos de la siguiente forma:
select *
from clientes
where exists (select *
from pedidos
where [id de cliente]=clientes.[id])
Vemos que en SQL se pueden hacer las mismas preguntas de muchas formas, la contraria es
decir los clientes que no tienen pedidos sera:
select *
from clientes
where not exists (select *
from pedidos
where [id de cliente]=clientes.[id])