7 - Elementos Del Lenguaje SQL 5
7 - Elementos Del Lenguaje SQL 5
Una operación de unión, como podremos imaginarnos a partir del nombre, realiza la unión
entre dos o más consultas distintas. Esta unión no se realiza de cualquier manera, sino que
para que la misma sea posible, todas las consultas a unir deben devolver los mismos
campos.
Las consultas de unión se realizan por medio del operador sql UNION. Este ofrece dos
variantes:
UNION: funciona como la operación unión de conjuntos, devuelve todos los registros de
ambas consultas, pero sin duplicados. Si existen registros repetidos, sólo devolverá una
instancia de los mismos. Repetido significa que todos los campos de ambos registros tienen
los mismos valores.
UNION ALL, por otro lado, no tiene esta restricción. Si un registro está repetido n veces,
devolverá n instancias del mismo.
Vamos a ver un ejemplo de consulta UNION. Para ellos, vamos a ampliar un poco nuestro
modelo farmacia con una tabla de pedidos y su detalle. Esta tabla contiene todos los
pedidos que aún no se han facturado. Suponemos que los pedidos sin facturar son los que
tienen el campo venta_numero en NULL.
-- Vamos a aumentar nuestro modelo con una tabla de pedidos y su detalle:
1
pedido_numero int,
producto_codigo int,
cantidad int,
primary key (pedido_numero, producto_codigo),
foreign key (pedido_numero) references pedido(numero),
foreign key (producto_codigo) references producto(c odigo)
);
Ahora realizaremos una consulta de unión entre la tabla venta y pedido, para conocer las
ventas realizadas y los pedidos pendientes de un cliente determinado:
select
'v' as tipo_operacion, v.numero, v.fecha
from
venta v
where
v.cliente_dni = 22222222
union
select
2
'p' as tipo_operacion, p.numero, p.fecha
from
pedido p
where
p.cliente_dni = 22222222
and p.venta_numero IS NULL;
Subqueries (Subconsultas)
Llamamos subqueries o subconsultas a las consultas que se realizan dentro del ámbito de
otra consulta. Generalmente se emplean para filtrar los resultados de la consulta principal
por medio de los resultados de la subconsulta o para crear un conjunto de resultados que se
empleará como “tabla virtual” a la que se aplicará la consulta principal.
Veamos un ejemplo:
select
fecha, numero
from
venta v
where
v.cliente_dni in (select
c.dni
from
cliente c
where
c. localidad_idlocalidad = 1);
3
que vivan en la localidad con idlocalidad=1. Para ello, empleamos los resultados de la
subconsulta para filtrar la consulta principal; esto se realiza con el operador IN, que lo que
hace es verificar si el valor del campo cliente_dni existe entre alguno de los devueltos por la
subconsulta. De este modo, la consulta principal devolverá sólo aquellos registros cuyo
cliente_dni se encuentre entre los dni devueltos por la subconsulta. Por supuesto que la
subconsulta deberá devolver sólo un campo, de lo contrario el motor de bases de datos no
sabría con cuál de los campos comparar el valor de cliente_dni.
Sin embargo, sabemos que este mismo resultado puede alcanzarse con una consulta join
común y corriente:
En muchos casos las consultas con subconsultas pueden reescribirse empleando alguna
clase de join y de hecho, en este caso la consulta con join es más sencilla. Además, hay
que tener cuidado con las subconsultas, porque dependiendo del optimizador del motor de
bases de datos, puede ocurrir que se ejecuten más lentamente que una consulta join
equivalente.
Entonces, ¿Para qué emplear subconsultas? Porque a pesar de lo dicho, tienen una
ventaja: cuando la consulta join es muy compleja, puede resultar más sencillo y legible
resolverlo por medio de subconsultas. En esos casos puede resultar conveniente escribir la
consulta empleando subconsultas y una vez que funcione correctamente, repensarla
empleando joins si tenemos un problema de performance. En los buenos motores de bases
de datos el optimizador se encarga de resolverlo, pero siempre convendrá asegurarse
recurriendo a la documentación del mismo.
Veamos otro ejemplo:
4
detalle_venta d
where
d.precio_unitario > (select
avg(p.precio)
from
producto p)
group by d.venta_numero;
En este caso la subconsulta devuelve un único valor, el promedio de los precios de todos
los productos. Ese valor es utilizado por la consulta externa para mostrar las ventas con un
artículo cuyo precio de venta resulte mayor que el promedio.
Otro ejemplo:
-- obtenemos los productos con precio mayor que el promedio de todos los
-- artículos vendidos. Tanto la consulta externa como la interna
-- se realizan sobre la misma tabla:
select
p.nombre, p.descripcion, p.precio
from
producto p
where
p.precio > (select
avg(p2.precio)
from
producto p2);
En este caso, la consulta externa y la interna se realizan sobre la misma tabla. Esto implica
que el motor de bases de datos realizará dos recorridos sobre la tabla: una para calcular el
promedio y otra para traer los registros que cumplan con la condición.
5
from
detalle_venta d
where
d.producto_codigo = p.codigo);
6
Vamos a ver un ejemplo un poco más complejo:
Vamos a analizar por partes lo que hace esta consulta. En primer lugar, vemos que se trata
de una consulta correlacionada, ya que empleamos un campo de la consulta externa en la
subconsulta (c.dni) . Por cada cliente de la consulta externa, la interna traerá las ventas
mayores a $200. Para ello, calcula la suma del precio por la cantidad, agrupando por
número de venta y filtrando por el cliente en cuestión. De los grupos formados, sólo deja
aquellos que al total resulte mayor que 200, por medio de la cláusula having (recordemos
que la cláusula having funciona para where pero para los registros agrupados).
Existe otro caso de subconsultas, aquellas en las que la consulta interna se encuentra en la
cláusula FROM. En este caso, podemos considerar a la misma como una tabla “virtual” de
la que traemos registros Esta tabla “virtual” se denomina interna o derivada. Por ejemplo:
select
max(items.cantidad_items) as maximo,
avg(items.cantidad_items) as promedio,
min(items.cantidad_items) as minimo
from
(select
d.venta_numero, count(d.venta_numero) as cantidad_items
from
detalle_venta d
7
group by d.venta_numero) as items;
8
Podemos ver que además de tener una subconsulta en el insert, la subconsulta en sí misma
posee una subconsulta, que no es otra que la que vimos dos consultas más atrás (págs
6-7). El resultado de dicha consulta (que nos devuelve a los clientes que compraron más de
$200) será el que insertaremos en la tabla cliente_importante.
delete
p.*
from
producto p
where
not exists(
select
d.venta_numero
from
detalle_venta d
where
d.producto_codigo = p.codigo);
En este caso, la consulta es similar a la que creamos para que nos devuelva los productos
sin vender (págs 5-6), pero cambiando select por delete. Si ejecutamos nuevamente dicha
consulta, no nos devolverá ningún registro: