Está en la página 1de 7

Examen Sistemas Informticos I, Septiembre 2004

Se desea disear un sistema de reserva de habitaciones para la universidad. El sistema


tiene que ser capaz de:
Proporcionar un listado con las habitaciones reservadas
Buscar reservas clasicndolas por
Fecha
Habitacin
Persona que ha realizado la reserva
Debe ser posible borrar registros y la base de datos debe mantenerse integra, esto es,
no puede existir una habitacin reservada a nombre de una persona cuyos datos no
estn almacenados en la tabla correspondiente. (Esta restriccin debe ser reforzada
por la base de datos no por el interfaz de usuario)
Los profesores y personal administrativo deben ser capaces de reservar cualquier tipo
de habitacin. Los estudiantes slo habitaciones de uso general (salones de actos).
(Esta restriccin debe ser reforzada por la base de datos no por el interfaz de
usuario)
Una habitacin no puede estar reservada por dos personas simultneamente. (Esta
restriccin debe ser reforzada por la base de datos no por el interfaz de usuario)
Los usuarios se identicarn con una clave.
(3 puntos) Disea RAZONADAMENTE una base de datos (diagrama entidad-relacin)
que satisfaga los requerimientos anteriores, as como efectuar consultas como las de las
preguntas siguientes. Se debern indicar las restricciones de integridad que contenga, y la
forma en que se especicarn en SQL tanto la estructura de las tablas como las restricciones
de integridad. En caso de que algn atributo pueda derivarse a partir de otros adjuntar la
consulta (en SQL) que proporcione el atributo redundante a partir del resto de los atributos
bsicos. En la medida de lo posible, la base de datos y no el interfaz de usuario se debe en-
cargar de todas las restricciones de integridad (mediante CHECKs, TRIGGERs, etc). Por
favor, ser breves en vuestros razonamientos pero es imprescindible que los hagais, un exa-
men que contenga solo el diagrama E-R y las tablas ser puntuado con zero.
(3 puntos) Dar RAZONADAMENTE consultas en el lgebra relacional y en SQL
que permitan realizar las siguientes operaciones (en SQL se valorar la eciencia de la
implementacin):
a) Supn que el diseo de la base de datos no es ptimo y que tras borrar un usuario
no se borran todas las reservas realizadas por el mismo. Escribe la/s consulta/s que da-
do un usuario con nombre=Pedro Prez elimine al usuario de la base de datos y todas
las reservas que haya realizado. En caso de que sea necesario escribir varias consultas,
1
deseamos que esta operacin sea atmica, esto es, se debe realizar o no realizar en su total-
idad. El cdigo SQL que escribas debe asegurar la atomicidad del proceso mediante el uso
de transacciones.
b) Para el mircoles 14 de Julio del 2004 de 13:30 a 15:30 Listar las habitaciones donde
se puedan alojar ms de 200 personas. El listado constar del identicador de habitacin
y de la palabra libre si la habitacin est libre o la direccin de correo electrnico de la
persona que la haya reservado. El listado debe estar ordenado de forma que primero salgan
las habitaciones libres y luego las ocupadas
(3 puntos) Escribir RAZONADAMENTE un programa en C que permita hacer reser-
vas. En particular el programa debe pedir al usuario que facilite los siguientes datos (Se
valorar la eciencia de la implementacin):
tipo de habitacin
fecha
hora de inicio
hora de nalizacin
numero de participantes
persona que realiza la reserva y clave
a continuacin proporcionar un listado como el del apartado b del punto anterior y permi-
tir al usuario que realice la reserva del aula que estime adecuada.
Recuerda que los estudiantes slo pueden reservar salones de actos, la base de datos
dar un error si se intenta violar esta restriccin. El programa debe procesar el error ade-
cuadamente e informar al usuario del problema.
(1 punto) Comenta BREVE y RAZONADAMENTE que haras para que se enviara
automaticamente un mail a la persona que ha realizado la reserva si esta es cancelada. No es
necesario que presentes la implementacin, sencillamente comenta como se podra hacer.
CALIFICACIONES: Se publicarn antes del 13 de septiembre
REVISIN DE EXMENES: 15 de septiembre a las 10:00 en el saln de grados
NOTA: No se revisarn exmenes a estudiantes que se presenten despus de la hora de
la revisin.
2
Diseo de base de datos para realizar reservas
La base se puede implementar usando dos entidades: habitacion y persona y una relacin
muchos a muchos reserva. Este diagrama da lugar a tres tablas.
-- tabla para la entidad habitacin.
-- Utiliza un comando check para restringir
-- el tipo de habitacion
CREATE TABLE habitacion (
habitacion_ID int,
habitacion_tipo varchar(128)
CHECK(
habitacion_tipo IN(
Clase,
Salon de Actos,
Sala de Juntas,
Salon de Grados
)
) NOT NULL,
capacidad int, --numero mximo de personas
PRIMARY KEY (habitacion_ID)
);
-- tabla para la entidad persona
CREATE TABLE persona (
persona_ID int, --podria usarse el DNI, entonces tendra que ser char
nombre varchar(128),
username varchar(128),--nombre de usuario
-- username es redundante con persona_ID
-- pero seguramente sera conveniente
-- en una aplicacion real
clave varchar(128),--password
Es_Alumno boolean DEFAULT t NOT NULL,
Telefono char(12),
email varchar(128),
PRIMARY KEY (persona_ID),
UNIQUE (username)
);
-- funcin que comprueba si la habitacin est disponible
-- la utilizar la tabla Reserva mediante un Check
-- Si la nueva reserva entra en conflicto con las reservas ya
-- almacenadas devuelve FALSE, en caso contrario TRUE
-- Se utiliza para implementar la restriccin Una habitacin no
-- puede estar reservada por dos personas simultneamente
CREATE OR REPLACE FUNCTION disponible(int,timestamp, timestamp) RETURNS bool AS
DECLARE myhabitacion_id ALIAS FOR $1;
mycomienzo ALIAS FOR $2;
myfin ALIAS FOR $3;
BEGIN
IF(EXISTS(
SELECT habitacion_ID
FROM reserva
WHERE habitacion_ID=myhabitacion_id AND (
(mycomienzo between comienzo_reserva AND fin_reserva) OR
(myfin between comienzo_reserva AND fin_reserva)
3
)
)
)
THEN
RETURN FALSE;
END IF;
RETURN TRUE;
END;
LANGUAGE plpgsql VOLATILE;
-- tabla que implementa la relacion reserva
-- se hace uso de la funcion disponible para asegurarse de que no
-- hay conflictos de horario al hacer la reserva
-- la linea:
-- FOREIGN KEY (persona_ID) REFERENCES persona (persona_ID) ON DELETE CASCADE
-- asegura la integridad de la base, si se borra una persona,
-- se borran todas las reservas que ha realizado
CREATE TABLE Reserva (
persona_ID int, -- persona que realiza la reserva
fecha_reserva date DEFAULT current_date, -- fecha en la que se realiza la reserva
comienzo_reserva timestamp, -- reserva empieza
fin_reserva timestamp, -- reserva termina
habitacion_ID int , -- habitacin reservada
number_of_participants int, -- No. participante estimado
FOREIGN KEY (persona_ID) REFERENCES persona (persona_ID) ON DELETE CASCADE,
FOREIGN KEY (habitacion_ID) REFERENCES habitacion (habitacion_ID) ON DELETE CASCADE,
CONSTRAINT habitacion_disponile CHECK (disponible(habitacion_ID,
comienzo_reserva,
fin_reserva))
);
-- trigger que comprueba que la reserva la ha hecho
-- una persona autorizada
-- Este codigo se ha implementado de forma que se pueda ejecutar
-- en postgres, lo cual es un poco mas restrictivo que el SQL 99
CREATE OR REPLACE FUNCTION autorizado_fun() RETURNS trigger AS
BEGIN
IF ( EXISTS (SELECT persona.persona_ID
FROM persona,habitacion,reserva
WHERE NEW.persona_ID=persona.persona_ID AND
Es_Alumno=t AND
habitacion_tipo NOT IN (Salon de Actos)
)
)
THEN RAISE EXCEPTION Usuario no autorizado;
END IF;
RETURN NEW;
END;
LANGUAGE plpgsql;
DROP TRIGGER autorizado ON member;
CREATE TRIGGER init_alta BEFORE INSERT ON Reserva
FOR EACH ROW EXECUTE PROCEDURE autorizado_fun();
4
Consultas
a)
SQL
--Es necesario:
-- a) Encontrar el valor del atributo persona_ID para Pedro Perez
-- b) Comenzar una transaccion
-- c) Borrar todas las reservas hechas por Pedro Perez
-- d) Borrar a Pedro Perez de la tabla de Personas
-- e) terminar la transaccin
-- en la base de datos de lo contrario el enunciado
-- est incompleto
BEGIN; -- or BEGIN TRANSACTION
CREATE VIEW USER_ID_Pedro_Perez AS
SELECT persona_ID
FROM persona
WHERE nombre=Pedro Perez;
DELETE from reserva
WHERE persona_ID IN (SELECT persona_ID
FROM persona
WHERE nombre=Pedro_Perez);
DELETE from persona
WHERE persona_ID IN (SELECT persona_ID
FROM persona
WHERE nombre=Pedro_Perez);
COMMIT; -- or END TRANSACTION
-- Mi diseo original era creando una vista para hallar el persona_ID
-- de Pedro Perez, pero Postgresql no lo daba por bueno,
-- por eso la vista USER_ID_Pedro_Perez no se usa
Algebra
USER_ID_Pedro_Perez
persona_id

nombre=

PedroPerez
persona
reserva reservaUSER_ID_Pedro_Perez reserva
persona personaUSER_ID_Pedro_Perez persona
b)
SQL
-- a) Seleccionar habitaciones con capacidad superior a 200 personas
-- b) Seleccionar habitaciones ocupadas el 14 de junio del 2004 de 13:30 a 15:3
-- c) Seleccionar habitaciones libres
-- d) imprimir segun el formato requerido
--a) habitaciones con capacidad para mas de 200 personas
CREATE VIEW habitaciones_mas_200 AS
5
SELECT habitacion_ID
FROM habitacion
WHERE capacidad > 200;
--habitaciones que pueden alojar a mas de 200 personas ocupadas
-- el mircoles 14 de Julio del 2004 entre las 13:30 y
-- las 15:30
CREATE VIEW habitaciones_ocupadas AS
SELECT reserva.habitacion_ID, email --el atributo email sera
--necesario despues
FROM reserva,habitaciones_mas_200,persona
WHERE ((2004-08-14 13:30:00 between comienzo_reserva AND fin_reserva)
OR (2004-08-14 15:30:00 between comienzo_reserva AND fin_reserva))
AND reserva.habitacion_ID=habitaciones_mas_200.habitacion_ID
AND reserva.persona_ID=persona.persona_ID;
--habitaciones libres
CREATE VIEW habitaciones_libres AS
SELECT habitacion_ID
FROM(
SELECT habitacion_ID
FROM habitaciones_mas_200
EXCEPT
SELECT habitacion_ID
FROM habitaciones_ocupadas
) AS alias_inutil
;
--Resultado Final
SELECT habitacion_ID, email
FROM
(
(SELECT habitacion_ID, libre AS email, 0 AS orden
FROM habitaciones_libres
UNION --OJO: union no garantiza ningun ordenamiento
SELECT habitacion_ID,email, 1 AS orden
FROM habitaciones_ocupadas
) ORDER BY order
) AS otro_alias_inutil;
Algebra
habitaciones_mas_200
habitacion_id

capacidad>200
habitacion
A reserva habitaciones_mas_200 persona
habitaciones_ocupadas
reserva.habitacion_id,email

(2004081413: 3

0 > comienzoreserva
AND2004081413: 30 < f inreserva)
OR(2004081415: 30 > comienzoreserva
AND2004081415: 30 < f inreserva)
A
B
habitacion_id
habitaciones_mas_200
C
habitacion_id
habitaciones_ocupadas
habitaciones_libres BC
D
(order)

E
(order)

6
DD
(email)

email

DDD
habitacion_id,email,order
habitaciones_libres DDDds f d f s
EEE
habitacion_id,email,order
habitaciones_ocupadas E

habitacion_id,email
DDDEEE
Nota 1: 0, 1, email son relaciones compuestas por una tupla y con un solo atributo,
el valor de la tupla es 0, 1 y email respectivamente.
Nota 2: En principio no existe la operacion ordenar en algebra relacional, una relacion
por denicin no tiene order y la salida de todos los operadores de algebra lineal que hemos
visto son relaciones.
Programa (vease chero adjunto solucion1.pgc)
Ultima pregunta
Usando sql estandard no es posible que una base de datos interaccione con el exterior
(mande mails, imprima etc). Una posibilidad seria crear una tabla email
DROP SEQUENCE email_id_seq;
CREATE SEQUENCE email_id_seq
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
SELECT setval(email_id_seq,0);
CREATE TABLE email (
id integer DEFAULT nextval(email_id_seq::text) NOT NULL,
"To" text NOT NULL,
"From" text NOT NULL,
"Subject" text NOT NULL,
"Message" text NOT NULL,
"Create_ON" date DEFAULT (now::text)::date,
PRIMARY KEY (id)
);
que se rellenaria automaticamente cada vez que se cancele una reserva mediante un trigger:
CREATE TRIGGER init_send_mail
AFTER DELETE ON reserva
FOR EACH ROW
EXECUTE PROCEDURE init_send_mail_fun();
CREATE FUNCTION init_send_mail_fun() RETURNS
-- aqui habria comandos para rellenar la tabla email
--
--
"trigger" AS
RETURN NEW;
END;

LANGUAGE plpgsql;
Finalmente un procedimiento externo gobernado por un cron deberia conectarse a la
base, leer la tabla de mails, enviarlos y borrar las entradas en la tabla. (Adjunto un ejemplo
de procedimiento externo escrito en python, vease chero sendmail.py)
7

También podría gustarte