Enunciado #
Una empresa opera garajes con reconocimiento de matrículas, barreras automáticas, sensores de ocupación y cobro automático. Admite abonados con suscripción y vehículos de rotación con ticket. Debe conservar accesos, ocupaciones, pagos, tarifas e incidencias, incluso cuando cambien las condiciones del servicio.
Datos que debes almacenar #
Se usan identificadores internos salvo que se indique una clave natural. Los campos opcionales deben admitir NULL. La lista fija nombres y tipos para poder comparar tu diseño con la solución del challenge.
Estructura y vehículos #
- Garaje:
id_garaje(entero),nombre(texto),direccion(texto),plazas_totales(entero). - Planta:
id_garaje(entero),num_planta(entero),plazas_disponibles(entero). - Plaza:
id_plaza(entero),id_garaje(entero),num_planta(entero),tipo(enum),tiene_cargador(boolean). - Propietario:
id_propietario(entero),nombre(texto),email(texto),telefono(texto). - Vehiculo:
matricula(texto),id_propietario(entero, opcional),tipo_vehiculo(texto),marca(texto),modelo(texto).
Abonos, tickets y cobros #
- Suscripcion:
id_suscripcion(entero),matricula(texto),id_garaje(entero),fecha_inicio(fechahora),fecha_fin(fechahora),tipo_abono(texto),id_plaza_asignada(entero, opcional). - Ticket:
id_ticket(entero),id_garaje(entero),matricula(texto, opcional),ts_entrada(fechahora),ts_salida(fechahora, opcional),importe_calculado(decimal, opcional),id_plaza(entero, opcional),id_tarifa(entero, opcional). - Pago:
id_pago(entero),id_ticket(entero, opcional),id_suscripcion(entero, opcional),ts_pago(fechahora),metodo(enum),importe(decimal). - Tarifa:
id_tarifa(entero),id_garaje(entero),vigencia_desde(fechahora),tipo(enum),regla(texto).
Dispositivos y actividad #
- Dispositivo:
id_dispositivo(entero),id_garaje(entero),tipo(enum),ubicacion(texto). - EventoAcceso:
id_evento(entero),id_dispositivo(entero),matricula(texto),ts_evento(fechahora),sentido(enum),resultado(enum). - OcupacionPlaza:
id_plaza(entero),ts_ocupa(fechahora),ts_libera(fechahora, opcional),matricula(texto, opcional),id_ticket(entero, opcional). - Incidencia:
id_incidencia(entero),id_dispositivo(entero),ts_incidencia(fechahora),severidad(enum),descripcion(texto),resuelta(boolean).
Claves, relaciones y reglas del negocio #
- La PK de
Plantaes(id_garaje, num_planta). Las demás tablas usan como PK su primer campo, salvoVehiculo, identificado pormatricula, yOcupacionPlaza, identificada por(id_plaza, ts_ocupa). - Identificación de plazas: se usa un
id_plazaglobalmente único. Cada plaza pertenece a una planta mediante la FK compuesta(id_garaje, num_planta)haciaPlanta. Esto evita referencias ambiguas cuando varios garajes o plantas usan la misma numeración local. - Cada propietario puede tener varios vehículos. Para admitir matrículas de rotación cuyo propietario no está registrado,
Vehiculo.id_propietarioes opcional. La matrícula detectada debe registrarse enVehiculoantes de referenciarla desde un evento. - Cada suscripción vincula una matrícula y un garaje durante el intervalo inclusivo
[fecha_inicio, fecha_fin]. Su identificador permite renovaciones. Una plaza asignada es opcional, debe pertenecer al mismo garaje y no puede reservarse a matrículas incompatibles en periodos solapados.tipo_abonoes texto abierto. - Un ticket pertenece a un garaje y puede tener matrícula y plaza desconocidas. Su salida, importe y tarifa se informan al cerrarlo. El tipo de plaza admite normal, PMR, EV y moto.
- Cada pago corresponde exactamente a un ticket o a una suscripción. Se sustituye la matrícula ambigua del pago del documento por
id_suscripcion, para identificar también qué abono o renovación se está pagando. La matrícula se obtiene del ticket o de la suscripción. Un ticket o suscripción puede recibir varios pagos;metodoadmite tarjeta, TPV o app. - Una tarifa pertenece a un garaje, tiene tipo ROTACION o ABONO y una regla de cálculo en texto. La combinación
(id_garaje, tipo, vigencia_desde)debe ser única; el editor no permite marcar esa unicidad compuesta por separado. Al cerrar un ticket, selecciona la tarifa ROTACION de ese garaje con el mayorvigencia_desdeque no superets_saliday conserva suid_tarifa. No modifiques retroactivamente una tarifa ya utilizada. - Cada dispositivo pertenece a un garaje y tiene tipo CAMARA, BARRERA o SENSOR. Cada evento referencia un dispositivo y una matrícula;
sentidoadmite ENTRADA o SALIDA yresultado, AUTORIZADO, DENEGADO o MANUAL. - Adaptación de integridad: el garaje de
EventoAccesose obtiene a través del dispositivo, sin duplicar unid_garajeque pudiera ser incoherente. Tampoco se almacena la fecha por separado: se calcula desdets_evento. Cada incidencia pertenece a un dispositivo; severidad admite baja, media, alta o critica. - Cada ocupación pertenece a una plaza. Usa
id_ticketpara la rotación, omatriculapara un abonado, de forma exclusiva. El ticket debe ser del mismo garaje y la matrícula de abonado debe tener una suscripción activa allí. Se puede volver a ocupar la misma plaza en otro instante. - Una plaza no puede tener dos ocupaciones abiertas ni intervalos de ocupación solapados.
ts_liberanulo deja el intervalo abierto. Estas reglas requieren índices parciales, restricciones de exclusión o validaciones transaccionales, según el motor; no marquesid_plazacomo único en todo el historial. - La autorización de acceso requiere una suscripción activa de la matrícula en ese garaje o un ticket abierto compatible. Una plaza reservada solo puede ocuparse por su matrícula mientras el abono esté activo. Un vehículo EV puede usar una plaza sin cargador, pero no cargar en ella.
- Al cerrar un ticket, sus pagos deben sumar al menos
importe_calculado. El importe y la tarifa deben estar informados. La coherencia entre plaza, garaje, tarifa, abono y ticket, y la suficiencia de los pagos, necesitan validación entre tablas. plazas_totalesyplazas_disponiblesse conservan como contadores materializados del documento: deben coincidir con las plazas y ocupaciones y actualizarse transaccionalmente. No son fuentes independientes de la capacidad y la ocupación.
Diseña las trece tablas. Además de las relaciones simples, conecta los dos campos de Plaza con la PK compuesta de Planta. Documenta las validaciones temporales y transaccionales que exceden el diagrama.
CHECK que debes configurar #
Escribe cada expresión exactamente en el campo indicado; los demás CHECK se dejan vacíos.
En Suscripcion, campo fecha_fin:
1fecha_fin >= fecha_inicio
En Ticket, campo ts_salida:
1ts_salida IS NULL OR ts_salida >= ts_entrada
En Ticket, campo importe_calculado:
1(importe_calculado IS NULL OR importe_calculado >= 0) AND (ts_salida IS NULL OR (importe_calculado IS NOT NULL AND id_tarifa IS NOT NULL))
En OcupacionPlaza, campo ts_libera:
1ts_libera IS NULL OR ts_libera >= ts_ocupa
En OcupacionPlaza, campo id_ticket:
1(id_ticket IS NOT NULL AND matricula IS NULL) OR (id_ticket IS NULL AND matricula IS NOT NULL)
En Pago, campo id_suscripcion:
1(id_ticket IS NOT NULL AND id_suscripcion IS NULL) OR (id_ticket IS NULL AND id_suscripcion IS NOT NULL)
Criterios para el challenge #
Conserva los nombres y tipos indicados. Todos los campos son obligatorios (NN) salvo los marcados como opcionales. Marca PK y FK según las reglas y las restricciones de unicidad indicadas. Una PK compuesta identifica por la combinación; no marques cada componente como único por separado.
Dibuja cada conexión desde el campo referenciado hacia la FK. Usa extremos 1 y n, o 1 y 1 para las relaciones de uno a uno. La opcionalidad se expresa con NN desmarcado en la FK. Si una FK es compuesta, dibuja una conexión por cada componente; en SQL todas esas columnas deben formar una única FOREIGN KEY hacia la misma fila.
Deja desactivados autoincremento, clave alternativa e índice. Deja vacíos valor por defecto, ON DELETE, ON UPDATE y CHECK, salvo los CHECK indicados expresamente. Las restricciones compuestas adicionales, los índices de explotación y las reglas entre varias filas se documentan aparte: el corrector del diagrama no ejecuta operaciones del negocio ni sustituye esas validaciones.