Profesores: Claudio Gutiérrez, Gonzalo Navarro
Prof. Auxiliar: Rodrigo Paredes
El álgebra relacional define nueve operaciones: unión,
intersección, diferencia y producto (que vienen de la teoría
de conjuntos de la matemática), selección, proyección,
reunión y división (que son las que se aplican específicamente
al modelo de datos relacional) y asignación (operación estándar
de los lenguajes de computación) que le da un valor a un nombre,
para la operación de asignación ocuparemos :=.
unión compatible: Dos o más relaciones que tienen columnas equivalentes en número y dominios.
Supongamos que:
VENDEDOR_SUBORDINADO {VENS_ID_VENDEDOR, VENS_NOMB_VENDEDOR, VENS_ID_JEFE,
VENS_OFICINA, VENS_COMISION}
VENDEDOR_JEFE {VENJ_ID_VENDEDOR, VENJ_NOMB_VENDEDOR, VENJ_ID_JEFE,
VENJ_OFICINA, VENJ_COMISION}
Si queremos calcular el conjunto de TODOS los vendedores:
VENDEDOR := VENDEDOR_SUBORDINADO
VENDEDOR_JEFE
Intersección :
Operación del álgebra relacional que crea un conjunto intersección
de dos relaciones unión compatibles.
Si queremos calcular el conjunto de los vendedores que son jefes y subordinados a la vez:
VENDEDOR_JEFE_SUBORDINADO := VENDEDOR_SUBORDINADO
VENDEDOR_JEFE
Diferencia -: Operación del álgebra relacional que crea un conjunto diferencia de dos relaciones unión compatibles. Ojo que la diferencia no es conmutativa.
Si queremos calcular quién (es) son jefe solamente (es decir, quien es el personaje que está en VENDEDOR_JEFE, pero que no está en VENDEDOR_SUBORDINADO):
VENDEDOR_JEFE_JEFE := VENDEDOR_JEFE - VENDEDOR_SUBORDINADO
Producto *: Operación del álgebra relacional que crea el producto cartesiano de dos relaciones.
si A{X, Y} tiene los siguientes elementos
|
|
|
|
y B{W, Z} contiene:
|
|
|
|
|
|
Entonces el producto de A y B es:
C := A * B
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ojo que si hacemos el producto cartesiano de dos relaciones que tienen un atributo en común, vamos a tener un problema con el nombre de la columna, para ello se recomienda como regla general que el nombre de un atributo esta compuesto por:
Si quisiéramos resolver la siguiente consulta: Dar toda la información de los vendedores en la oficina de Tokyo.
VEND_TOKYO := SELECT (VENDEDOR : VEND_OFICINA = 'Tokyo')
Noten que las condiciones de selección (las que van después del ':') son similares a las usadas en la instrucciones IF.
Consulta: ¿Qué vendedores tienen ID 23?
SELECT (VENDEDOR : VEND_ID_VENDEDOR = 23)
Consulta: ¿Qué vendedores tienen trabajan en Tokio y tienen
comisión superior a 11%?
SELECT (VENDEDOR : VEND_OFICINA = 'Tokyo' and VEND_COMISION > 11)
Proyección [.]: Operación del álgebra relacional que crea una relación borrando columnas de una relación existente.
A[X]
10
11
Ojo que la proyección genera conjuntos, luego si en la tabla original la subtupla seleccionada se repite, al proyectar sólo vemos la fila una vez.
Consulta: ¿Quiénes son los vendedores que tienen una comisión menor que 20%?
SELECT (VENDEDOR : VEND_COMISION < 11) [VEND_NOMBRE]
Reunión JOIN: Operación del álgebra relacional que conecta relaciones.
Hay tres casos:
Consulta: Adjunte la información de las ventas a la información
sobre los vendedores.
JOIN(VENDEDOR, VENTA)
Consulta: Indique los nombres de los clientes que han comprado el producto
2518
A := SELECT (VENTA: VTA_ID_PROD = 2518)
B := JOIN (A, CLIENTE) [CLI_NOMBRE]
Consulta: ¿Quiénes han comprado lámparas de mesa?
A := SELECT (PRODUCTO : DESCRIPCION = 'lámpara de mesa')
B := JOIN (A, VENTA)
C := JOIN (B, CLIENTE) [CLI_NOMBRE]
Reunión theta: Considere la siguiente consulta:
Consulta: ¿Identifique los vendedores cuyos jefes obtienen una tasa de comisión por encima del 11%?
Para esto tenemos que hacer un JOIN de la tabla VENDEDORES con la tabla VENDEDORES !!, porque así podemos encontrar directamente cual es la comisión del jefe, pero el join natural intentara calzar todos los atributos (porque ambas tablas tienen los mismos atributos, es más es la misma tabla), así que haremos un JOIN pero especificando los atributos de calce.
VEND1 := VENDEDOR
VEND2 := VENDEDOR
A := JOIN
(VEND1, VEND2 : VEND1.VEND_ID_JEFE = VEND2.VEND_ID_VENDEDOR)
B := SELECT
(A : VEND2.VEND_COMISION > 11) [VEND1.VEND_NOMBRE]
Reunión externa: Primero se ejecuta una reunión natural. Entonces si un registro en una relación no se corresponde con un registro de la otra relación en la reunión natural, ese registro se añade a la relación que ha sido reunida y las columnas adicionales se llenan con valores nulos.
Consulta: Adjunte la información de las ventas a la información sobre los vendedores.
Solución inicial: JOIN (VENDEDOR, VENTA)
¿Pero qué pasa con los vendedores que no han hecho ventas?
OUTERJOIN (VENDEDOR, VENTA) :)
División /: Operación del álgebra relacional que crea una nueva relación, seleccionando las filas en una relación que se corresponden con todas las filas en otra relación.
Consulta: Liste los vendedores que han vendido todos los productos.
PI := PRODUCTO [PROD_ID_PRODUCTO]
PI_VI := VENTA [PROD_ID_PRODUCTO, VTA_ID_VENDEDOR]
A := PI_VI / PI
Noten que en A sólo queda la columna VTA_ID_VENDEDOR, y se listan sólo los vendedores que han vendido a todos los productos.
¿Cuáles son los nombres de los clientes que han enviado
paquetes a la ciudad de Sioux, Iowa?
A := JOIN(CLIENTE,EMBARQUE : CLI_ID = EMB_CLI_ID) | equivalente al JOIN(CLIENTE,EMBARQUE) porque el atributo CLI_ID es el mismo que EMB_ID_CLI |
B := SELECT (A : EMB_DESTINO = 'Sioux') | En B guardo las filas que llegan a Sioux |
C := SELECT (A : EMB_DESTINO = 'Sioux') | En C guardo las filas que llegan a Iowa |
D := B![]() |
Unión de dos relaciones unión compatibles |
Respuesta := D[CLI_NOMB] | Me quedo con los nombre solamente |
¿A qué destinos han enviado paquetes los clientes con
renta anual inferior a un millón
A := SELECT (CLIENTE : CLI_RENTA < 1000000) [CLI_ID] | Calculo los clientes que tienen menos de un millón de renta, y sólo me quedo con el identificador |
Respuesta := JOIN (A, EMBARQUE) [EMB_DESTINO] | Hago el join de A con la relación de embarques |
¿Cuáles son los nombres de la ciudades que han recibido
envíos que pesan más de 100 libras?
A := SELECT (EMBARQUE : EMB_PESO > 100) [EMB_DESTINO] | Selecciono los envíos que me interesan, y luego el identificador del destino |
Respuesta := JOIN (A, CIUDAD) [CIU_NOMBRE] |
Las ciudades que han recibido embarques de clientes que tienen una renta
anual por encima de los 15 millones.
A := SELECT (CLIENTE : CLI_RENTA_ANUAL > 15000000) [CLI_ID] | El id de los clientes con renta > 15000000 |
B := JOIN (A, EMBARQUES) [EMB_DESTINO] | El id de las ciudades |
Respuesta := JOIN (B, CIUDAD) [CIU_NOMBRE] |
Clientes que han tenido envíos distribuidos por todos los choferes
A := CAMION[CAM_NOMBRE_CHOFER] | Preparo el divisor |
B := JOIN (EMBARQUES, CAMION) [EMB_ID_CLI, CAM_NOMBRE_CHOFER] | Preparo el dividendo |
C := B / A | Hago la división |
Respuesta := JOIN(C,CLIENTE) [NOMB_CLIENTE] |
Clientes que envían todos sus embarques a una única ciudad
A := EMBARQUES [EMB_ID_CLI, EMB_DESTINO] | Guardo las subtuplas que me interesan |
B := A | |
C := A * B | C es el producto cartesiano de A con B |
D := SELECT (C : A.EMB_ID_CLI = B.EMB_ID_CLI) | D guarda las filas de C con igual nombre de cliente |
E := SELECT (D : A.EMB_DESTINO not = B.EMB_DESTINO) | Me quedo con las filas de D con destino diferente |
F := E[A.EMB_ID_CLI] | Estos son los nombres de los clientes con más de un destino |
G := EMBARQUE[EMB_ID_CLI] | Estos son los clientes que hacen envíos |
H := G - F | Acá quedan los clientes con 1 destino |
Respuesta := JOIN(H, CLIENTE)[CLI_NOMBRE] | Uf!!, terminamos |