CC42A: Bases de datos Auxiliar: Álgebra Relacional Profesores: Claudio Gutiérrez, Gonzalo Navarro Prof. Auxiliar: Rodrigo Paredes Parte 1. Álgebra relacional El Álgebra Relacional es un lenguaje procedural para la manipulación de relaciones. 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 :=. Primero veamos los que vienen de la teoría de conjuntos Unión : Operación del álgebra relacional que crea un conjunto unión de dos relaciones unión compatibles. 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 10 22 11 25 y B{W, Z} contiene: 33 54 37 98 42 100 Entonces el producto de A y B es: C := A * B 10 22 33 54 10 22 37 98 10 22 42 100 11 25 33 54 11 25 37 98 11 25 42 100 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: 1. Una sigla que hace referencia al nombre de la relación 2. Un subrayado 3. El nombre del atributo Ejemplo: PRODUCTO {PROD_ID_PROD, PROD_NOMBRE, ...} VENTA {VTA_ID_PROD, VTA_FECHA, ...} Específicas del álgebra relacional Selección SELECT: Operación del álgebra relacional que usa una condición para seleccionar filas de una relación. 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: 1. Reunión natural : Operación de reunión que conecta relaciones cuando las columnas comunes tienen iguales valores. 2. Reunión theta: Operación de reunión que conecta relaciones cuando los valores de determinadas columnas tienen una interrelación específica. 3. Reunión externa: Expansión de la reunión natural que incluye todas las filas de ambas relaciones. Reunión natural: Noten que la reunión natural hace la asociación de las llaves y atributos comunes solita, no hay que especificar nada. 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. Operador de asignación Ya vimos que se usa para guardar nuevas relaciones que se generan mediante el uso de los operadores del álgebra relacional, y utiliza el símbolo :=. Parte 2. Ejemplos P1.- Consulta: ¿Cuál es la máxima tasa de comisión? A := VENDEDOR [VEND_COMISION] B := VENDEDOR [VEND_COMISION] C := JOIN (A, B: A.VEND_COMISION > B.VEND_COMISION) D := C [B.VEND_COMISION] // acá me quedo con la comisión menor :) E := A - D P2.- Considere el siguiente esquema: CLIENTE{CLI_ID, CLI_NOMB, CLI_RENTA_ANUAL} EMBARQUE{EMB_ID, EMB_ID_CLI, EMB_PESO, EMB_ID_CAMION, EMB_DESTINO} Clave Foránea: EMB_CLI_ID referencia a CLI_ID en CLIENTE ¿Cuáles son los nombres de los clientes que han enviado paquetes a la ciudad de Sioux, Iowa? A := JOIN(CLIENTE,EMBARQUE : equivalente al JOIN(CLIENTE,EMBARQUE) porque el CLI_ID = EMB_CLI_ID) atributo CLI_ID es el mismo que EMB_ID_CLI B := SELECT (A : EMB_DESTINO = En B guardo las filas que llegan a Sioux 'Sioux') C := SELECT (A : EMB_DESTINO = En C guardo las filas que llegan a Iowa 'Sioux') D := B C 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 P3.- Considere el siguiente esquema: CLIENTE{CLI_ID, CLI_NOMB, CLI_RENTA_ANUAL} EMBARQUE{EMB_ID, EMB_ID_CLI, EMB_PESO, EMB_ID_CAMION, EMB_DESTINO} Clave Foránea: EMB_CLI_ID referencia a CLI_ID en CLIENTE Clave Foránea: EMB_DESTINO referencia a CIU_NOMBRE en CIUDAD Clave Foránea: EMB_ID_CAMION referencia a CAM_ID en CAMION CAMION{CAM_ID, CAM_NOMBRE_CHOFER} CIUDAD{CIU_NOMBRE, CIU_POBLACION} ¿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 = Me quedo con las filas de D con destino B.EMB_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