diff --git a/resoluciones/maria-montepeque/ejercicio-69/README.md b/resoluciones/maria-montepeque/ejercicio-69/README.md new file mode 100644 index 00000000..00d4a67f --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-69/README.md @@ -0,0 +1,75 @@ +# Ejercicio 69: DROP Nivel Intermedio + +**Nombre:** Maria Jose Montepeque +**Fecha:** 2026-08-21 + +## Descripcion del problema + +Una clinica agenda citas relacionando pacientes con medicos. La lista +de medicos llego en una tabla temporal de importacion que, una vez +migrada a la tabla definitiva, ya no sirve para nada. Ademas, la clinica +necesita entender que pasa si intenta eliminar una tabla (`medicos`) que +todavia tiene citas dependiendo de ella por `FOREIGN KEY`. + +## Tablas y relaciones + +- `medicos`: catalogo de medicos, tabla definitiva y permanente. +- `pacientes`: catalogo de pacientes. +- `citas`: relaciona un paciente con un medico en una fecha, con un + estado. `pacientes` 1—N `citas`; `medicos` 1—N `citas`. + +## Uso de DROP + +En `ddl/schema.sql`, despues de crear las 3 tablas y migrar los datos de +medicos desde una tabla temporal de importacion, y de registrar +pacientes y citas: + +1. `DROP TABLE medicos_temporal;`: elimina la tabla temporal una vez que + sus datos ya se copiaron a `medicos`. El riesgo real de `DROP` se + explica en un comentario: ejecutarlo antes de migrar los datos + habria perdido esa informacion para siempre. +2. `CREATE VIEW vista_citas_atendidas ...` seguido de + `DROP VIEW vista_citas_atendidas;`: se crea una vista de apoyo para + un reporte puntual y se elimina cuando ya no se va a reutilizar. + `DROP VIEW` no afecta los datos de `citas`, `pacientes` ni `medicos`. + +La consulta 5 en `dql/consultas.sql` confirma, consultando +`sqlite_master`, que la tabla temporal y la vista ya no existen, +mientras que los 2 medicos migrados siguen disponibles en `medicos`. + +## Otras restricciones aplicadas + +- `PRIMARY KEY` autoincremental en las 3 tablas. +- `FOREIGN KEY`: `citas.id_paciente`, `citas.id_medico`. +- `NOT NULL` en todas las columnas obligatorias. +- `UNIQUE`: `medicos.nombre`, `pacientes.telefono`. +- `CHECK`: `citas.estado IN (...)`. +- `DEFAULT` en `citas.estado`. +- `PRAGMA foreign_keys = ON;` activado al inicio del script. + +## Caso que falla / no recomendable (comentado en `ddl/schema.sql`) + +`DROP TABLE medicos;` falla porque `citas` todavia tiene filas que +dependen de `medicos` por `FOREIGN KEY`, y SQLite (con +`PRAGMA foreign_keys = ON`) no permite eliminar una tabla que sigue +siendo referenciada. Se valido ejecutandolo con Python (`sqlite3`): +lanza `IntegrityError: FOREIGN KEY constraint failed`. Para poder +eliminar `medicos` habria que primero eliminar o reasignar las citas +que dependen de ella (o eliminar `citas` antes que `medicos`). + +## Evidencias de ejecucion + +Scripts validados en orden (`ddl` -> `inserts` -> `consultas`) con +Python (modulo `sqlite3`), ya que no se tenia el binario `sqlite3` +disponible en el entorno. Detalle completo en +[`evidencias/resultados.md`](evidencias/resultados.md). + +- Datos finales: 2 medicos, 4 pacientes, 4 citas. + +## Como ejecutar + +```bash +sqlite3 ejercicio-69.db < ddl/schema.sql +sqlite3 ejercicio-69.db < dml/inserts.sql +sqlite3 ejercicio-69.db < dql/consultas.sql +``` diff --git a/resoluciones/maria-montepeque/ejercicio-69/ddl/schema.sql b/resoluciones/maria-montepeque/ejercicio-69/ddl/schema.sql new file mode 100644 index 00000000..6033b7ad --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-69/ddl/schema.sql @@ -0,0 +1,82 @@ +PRAGMA foreign_keys = ON; + +-- Ejercicio 69: DROP Nivel Intermedio +-- Tema central: DROP +-- Contexto: agenda de citas medicas por fecha. + +-- Tablas principales, permanentes. +CREATE TABLE medicos ( + id_medico INTEGER PRIMARY KEY AUTOINCREMENT, + nombre TEXT NOT NULL UNIQUE, + especialidad TEXT NOT NULL +); + +CREATE TABLE pacientes ( + id_paciente INTEGER PRIMARY KEY AUTOINCREMENT, + nombre TEXT NOT NULL, + telefono TEXT NOT NULL UNIQUE +); + +CREATE TABLE citas ( + id_cita INTEGER PRIMARY KEY AUTOINCREMENT, + id_paciente INTEGER NOT NULL, + id_medico INTEGER NOT NULL, + fecha_cita TEXT NOT NULL, + estado TEXT NOT NULL DEFAULT 'programada' + CHECK (estado IN ('programada', 'atendida', 'cancelada')), + + FOREIGN KEY (id_paciente) REFERENCES pacientes (id_paciente), + FOREIGN KEY (id_medico) REFERENCES medicos (id_medico) +); + +-- Tabla temporal de importacion: la clinica recibio el listado de +-- medicos en un formato plano, sin las restricciones finales, y se uso +-- esta tabla solo para migrar los datos a la tabla definitiva. +CREATE TABLE medicos_temporal ( + nombre_bruto TEXT, + especialidad_bruta TEXT +); + +INSERT INTO medicos_temporal (nombre_bruto, especialidad_bruta) VALUES + ('Dra. Sofia Ramirez', 'Medicina General'), + ('Dr. Carlos Perez', 'Pediatria'); + +INSERT INTO medicos (nombre, especialidad) +SELECT nombre_bruto, especialidad_bruta FROM medicos_temporal; + +INSERT INTO pacientes (nombre, telefono) VALUES + ('Manuel Estrada', '5555-7001'), + ('Alejandra Chinchilla', '5555-7002'), + ('Byron Xicay', '5555-7003'); + +INSERT INTO citas (id_paciente, id_medico, fecha_cita, estado) VALUES + (1, 1, '2026-08-01 09:00', 'atendida'), + (2, 2, '2026-08-01 10:30', 'atendida'), + (3, 1, '2026-08-02 08:00', 'programada'); + +-- DROP TABLE: la tabla de importacion ya cumplio su proposito (los +-- datos ya viven en `medicos`) y se elimina para no dejar datos +-- duplicados. Este es el riesgo de DROP: si se ejecutara antes de +-- migrar los datos, esa informacion se perderia para siempre. +DROP TABLE medicos_temporal; + +-- Vista de apoyo para un reporte puntual de citas ya atendidas... +CREATE VIEW vista_citas_atendidas AS + SELECT c.id_cita, p.nombre AS paciente, m.nombre AS medico, c.fecha_cita + FROM citas c + JOIN pacientes p ON p.id_paciente = c.id_paciente + JOIN medicos m ON m.id_medico = c.id_medico + WHERE c.estado = 'atendida'; + +-- ...y una vez entregado el reporte, se elimina porque ya no se va a +-- reutilizar. DROP VIEW solo borra la definicion de la vista: los datos +-- de `citas`, `pacientes` y `medicos` siguen intactos. +DROP VIEW vista_citas_atendidas; + +-- Caso que debe fallar / no recomendable (queda comentado): intentar +-- eliminar una tabla que todavia esta referenciada por FOREIGN KEY +-- desde otra tabla con filas. SQLite, con PRAGMA foreign_keys = ON, no +-- permite este DROP mientras existan citas que dependan de medicos: hay +-- que eliminar o reasignar esas citas primero (o eliminar la tabla +-- `citas` antes que `medicos`). +-- DROP TABLE medicos; diff --git a/resoluciones/maria-montepeque/ejercicio-69/dml/inserts.sql b/resoluciones/maria-montepeque/ejercicio-69/dml/inserts.sql new file mode 100644 index 00000000..820e84dc --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-69/dml/inserts.sql @@ -0,0 +1,12 @@ +PRAGMA foreign_keys = ON; + +-- Ejercicio 69: DROP Nivel Intermedio +-- Se ejecuta despues de que ddl/schema.sql migro los datos de medicos y +-- elimino la tabla temporal y la vista de apoyo. Aqui solo se agregan +-- registros nuevos directamente a las tablas definitivas. + +INSERT INTO pacientes (nombre, telefono) VALUES + ('Cristina Barrios', '5555-7004'); + +INSERT INTO citas (id_paciente, id_medico, fecha_cita, estado) VALUES + (4, 2, '2026-08-03 11:00', 'programada'); diff --git a/resoluciones/maria-montepeque/ejercicio-69/dql/consultas.sql b/resoluciones/maria-montepeque/ejercicio-69/dql/consultas.sql new file mode 100644 index 00000000..a4deeabb --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-69/dql/consultas.sql @@ -0,0 +1,40 @@ +.headers on +.mode column + +-- Ejercicio 69: DROP Nivel Intermedio +-- Consultas de validacion. + +-- 1. Mostrar todos los datos principales (citas con paciente y medico). +SELECT c.id_cita, p.nombre AS paciente, m.nombre AS medico, + c.fecha_cita, c.estado +FROM citas c +JOIN pacientes p ON p.id_paciente = c.id_paciente +JOIN medicos m ON m.id_medico = c.id_medico; + +-- 2. Consulta con WHERE: citas ya atendidas. +SELECT id_cita, fecha_cita +FROM citas +WHERE estado = 'atendida'; + +-- 3. Consulta con ORDER BY: citas ordenadas por fecha. +SELECT id_cita, fecha_cita, estado +FROM citas +ORDER BY fecha_cita; + +-- 4. Conteo o resumen: total de citas por estado. +SELECT estado, COUNT(*) AS total +FROM citas +GROUP BY estado; + +-- 5. Validacion especifica de DROP: la tabla temporal de medicos y la +-- vista de reporte que se usaron y luego se eliminaron ya no existen en +-- el catalogo de la base de datos, pero los 2 medicos migrados desde la +-- tabla temporal si siguen ahi. +SELECT name, type +FROM sqlite_master +WHERE name IN ('medicos_temporal', 'vista_citas_atendidas'); +-- Debe devolver 0 filas: los 2 objetos se eliminaron con DROP. + +SELECT nombre, especialidad +FROM medicos; +-- Los 2 medicos migrados desde la tabla temporal siguen disponibles. diff --git a/resoluciones/maria-montepeque/ejercicio-69/evidencias/resultados.md b/resoluciones/maria-montepeque/ejercicio-69/evidencias/resultados.md new file mode 100644 index 00000000..f1ac806a --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-69/evidencias/resultados.md @@ -0,0 +1,65 @@ +# Evidencias - Ejercicio 69 + +## Tema + +DROP + +## Comandos ejecutados + +No se conto con el binario `sqlite3` en el entorno de trabajo, por lo que +la ejecucion se valido con Python (`sqlite3`), aplicando los mismos +scripts en el mismo orden: + +```bash +sqlite3 ejercicio-69.db < ddl/schema.sql +sqlite3 ejercicio-69.db < dml/inserts.sql +sqlite3 ejercicio-69.db < dql/consultas.sql +``` + +## Resultados + +Estado justo despues de `ddl/schema.sql` (migracion + DROP de tabla +temporal y vista): + +```text +medicos: [(1, 'Dra. Sofia Ramirez', 'Medicina General'), + (2, 'Dr. Carlos Perez', 'Pediatria')] + +sqlite_master (tabla temporal, vista): [] -- ya no existen +``` + +Caso que debe fallar (comentado en `ddl/schema.sql`): + +```text +DROP TABLE medicos; +Fallo como se esperaba: IntegrityError: FOREIGN KEY constraint failed +``` + +Estado final (despues de `inserts.sql`), 4 citas en total: + +```text +estado total +atendida 2 +programada 2 +``` + +Consulta 5 (validacion especifica de DROP): + +```text +5a. sqlite_master para los 2 objetos eliminados: sin filas +5b. medicos migrados desde la tabla temporal, siguen disponibles: + ('Dra. Sofia Ramirez', 'Medicina General') + ('Dr. Carlos Perez', 'Pediatria') +``` + +## Aprendizaje + +Ademas de lo visto en el nivel basico (migrar y luego eliminar una +tabla temporal, o eliminar una vista de apoyo sin afectar los datos), +este ejercicio mostro un limite importante de `DROP` en un modelo con +relaciones: SQLite, con `PRAGMA foreign_keys = ON`, no permite eliminar +una tabla que todavia esta referenciada por `FOREIGN KEY` desde otra +tabla con filas. Esto protege contra dejar datos huerfanos (citas +apuntando a un medico que ya no existe) y obliga a pensar el orden +correcto: eliminar primero las filas o tablas dependientes antes de +eliminar la tabla que referencian. diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/README.md b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/README.md new file mode 100644 index 00000000..b2a86308 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/README.md @@ -0,0 +1,83 @@ +# Ejercicio 069: Solicitud de cliente - Diseno 3D Arquitectura + +**Nombre:** Maria Jose Montepeque +**Fecha:** 2026-08-21 + +## Que entendi de la solicitud + +El estudio necesita guardar historico porque en auditorias le preguntan +que paso y cuando paso. Se necesita una base de datos que permita +consultar renders y su historial de revisiones, corregir estados, +registrar movimientos y sacar reportes, como saber que proyecto +requirio mas revisiones o cuales estan listos para entrega. El detalle +completo del analisis esta en +[`analisis/requerimiento.md`](analisis/requerimiento.md). + +## Tablas y por que se crearon + +- `clientes`: catalogo de quien contrata cada proyecto. +- `proyectos`: proyecto de diseno para un cliente. +- `renders`: tabla transaccional; imagen generada para un proyecto. +- `revisiones`: **historico de auditoria**; cada revision de un render + se conserva con su fecha y resultado, nunca se borra. +- `entregas`: version formal del proyecto entregada al cliente. + +## Como se relacionan + +`clientes` 1—N `proyectos`; `proyectos` 1—N `renders`; `renders` 1—N +`revisiones`; `proyectos` 1—N `entregas`. + +## Datos de prueba + +3 clientes, 4 proyectos, 9 renders (uno de ellos duplicado por error, +sin revisiones todavia), 12 revisiones y 4 entregas. + +## Operaciones (`dml/operaciones.sql`) + +- `UPDATE`: un render `'en_proceso'` termina y pasa a `'terminado'`. +- `UPDATE`: se corrige un comentario de revision con error de captura + **sin eliminarlo**, para conservar el historico de auditoria tal + como pidio el cliente. +- `DELETE` controlado (con `WHERE`): se elimina un render duplicado + creado por error, que todavia no tenia ninguna revision asociada. + Este es el unico caso del modelo donde un `DELETE` real es aceptable; + el resto del historico nunca se borra. +- Caso comentado que debe fallar: eliminar un render que ya tiene + revisiones asociadas viola la `FOREIGN KEY` de + `revisiones.id_render`. + +## Consultas que responden al cliente + +1. Todos los renders con su proyecto y cliente (`JOIN`). +2. Renders filtrados por estado (`en_proceso`, `terminado`, + `descartado`). +3. Ranking de proyectos por numero de revisiones -- el historico de + auditoria (`GROUP BY` + `ORDER BY`). +4. Revisiones ordenadas por fecha, de la mas reciente a la mas antigua. +5. Reporte de decision de negocio: proyectos con renders aprobados, + para saber cuales estan listos para su proxima entrega + (`GROUP BY` + `HAVING`). + +## Evidencias de ejecucion + +Scripts validados en orden (`ddl` -> `inserts` -> `operaciones` -> +`consultas`) con Python (modulo `sqlite3`), ya que no se tenia el +binario `sqlite3` disponible en el entorno. Detalle completo en +[`evidencias/resultados.md`](evidencias/resultados.md). + +- Datos base: 3 clientes, 4 proyectos, 9 renders, 12 revisiones, 4 + entregas. +- Tras `operaciones.sql`: 8 renders (se elimino el duplicado sin + historico), render 3 terminado, comentario de revision corregido sin + perder el registro. +- Reporte final: "Casa Vista Verde" es el proyecto con mas renders + aprobados (2). + +## Como validar + +```bash +sqlite3 ejercicio-069.db < ddl/schema.sql +sqlite3 ejercicio-069.db < dml/inserts.sql +sqlite3 ejercicio-069.db < dml/operaciones.sql +sqlite3 ejercicio-069.db < dql/consultas.sql +``` diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/analisis/requerimiento.md b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/analisis/requerimiento.md new file mode 100644 index 00000000..f39046da --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/analisis/requerimiento.md @@ -0,0 +1,69 @@ +# Analisis del requerimiento - Ejercicio 069 + +## Solicitud entendida + +Un estudio de diseno 3D de arquitectura registra clientes, proyectos, +renders, revisiones y entregas. El cliente necesita guardar historico +porque en auditorias le preguntan que paso y cuando paso: por eso el +modelo no debe borrar informacion de proceso (revisiones), sino +conservarla con su fecha y su resultado. Se necesita una base de datos +que permita consultar datos, corregir estados, registrar movimientos y +sacar reportes, por ejemplo saber que proyecto requirio mas revisiones. + +## Entidades detectadas + +| Entidad | Por que existe | Atributos importantes | +| --- | --- | --- | +| clientes | Catalogo: quien contrata el proyecto | nombre, telefono (unico) | +| proyectos | Catalogo/operacion: proyecto de diseno para un cliente | nombre, tipo, fecha_inicio | +| renders | Tabla transaccional: imagen o render generado para un proyecto | nombre_archivo, fecha_creacion, estado | +| revisiones | Historico de auditoria: cada revision de un render se conserva, no se borra | comentario, fecha_revision, aprobado | +| entregas | Movimiento: version del proyecto entregada formalmente al cliente | fecha_entrega, version | + +## Relaciones detectadas + +| Relacion | Tipo | Explicacion | +| --- | --- | --- | +| clientes -> proyectos | 1:N | Un cliente puede tener varios proyectos. | +| proyectos -> renders | 1:N | Un proyecto puede generar varios renders. | +| renders -> revisiones | 1:N | Un render puede tener varias revisiones a lo largo del tiempo (esto es el historico que pide el cliente). | +| proyectos -> entregas | 1:N | Un proyecto puede tener varias entregas formales (version 1, version 2, etc.). | + +## Reglas de negocio + +- Regla 1: para conservar el historico de auditoria, una revision + **nunca se elimina**; si una revision fue un error de captura real, + se corrige con `UPDATE`, no con `DELETE`. El unico `DELETE` permitido + en este modelo es sobre un render que se creo por error y todavia no + tiene ninguna revision asociada. +- Regla 2: un render nace `'en_proceso'` y solo puede avanzar a + `'terminado'` o `'descartado'` (`CHECK`). +- Regla 3: `revisiones.aprobado` es una bandera (0 o 1) que registra si + esa revision especifica aprobo el render en ese momento (`CHECK`). +- Regla 4: el tipo de proyecto debe ser uno de los reconocidos por el + estudio (`CHECK (tipo IN ('residencial', 'comercial', 'institucional'))`). +- Regla 5: el telefono de un cliente no se puede repetir (`UNIQUE`). + +## Supuestos + +- El cliente no especifico si una entrega incluye varios renders a la + vez; se asume que `entregas` registra la version formal entregada del + proyecto en su conjunto, no render por render. +- No se detallo quien hace cada revision; se asume que ese dato no es + indispensable para el alcance de este modelo (podria agregarse una + tabla `revisores` en una version futura). +- Se asume que un render `'descartado'` puede seguir teniendo + revisiones en su historico (no se elimina su historial aunque el + render ya no se use). + +## Preguntas que responde la base de datos + +1. Cuales son todos los renders con su proyecto y cliente. +2. Que renders estan en proceso, terminados o descartados. +3. Que proyecto tiene mas actividad (ranking por numero de revisiones, + el historico de auditoria). +4. Cuales son las revisiones ordenadas por fecha, de la mas reciente a + la mas antigua. +5. Que proyectos tienen mas renders aprobados en su ultima revision + (reporte para decision de negocio: que proyectos estan listos para + entrega). diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/ddl/schema.sql b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/ddl/schema.sql new file mode 100644 index 00000000..800d570e --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/ddl/schema.sql @@ -0,0 +1,53 @@ +PRAGMA foreign_keys = ON; + +-- Ejercicio 069: Diseno 3D Arquitectura +-- Modelo: clientes, proyectos, renders, revisiones, entregas + +CREATE TABLE clientes ( + id_cliente INTEGER PRIMARY KEY AUTOINCREMENT, + nombre TEXT NOT NULL, + telefono TEXT NOT NULL UNIQUE +); + +CREATE TABLE proyectos ( + id_proyecto INTEGER PRIMARY KEY AUTOINCREMENT, + id_cliente INTEGER NOT NULL, + nombre TEXT NOT NULL, + tipo TEXT NOT NULL CHECK (tipo IN ('residencial', 'comercial', 'institucional')), + fecha_inicio TEXT NOT NULL DEFAULT (date('now')), + + FOREIGN KEY (id_cliente) REFERENCES clientes (id_cliente) +); + +CREATE TABLE renders ( + id_render INTEGER PRIMARY KEY AUTOINCREMENT, + id_proyecto INTEGER NOT NULL, + nombre_archivo TEXT NOT NULL, + fecha_creacion TEXT NOT NULL DEFAULT (datetime('now')), + estado TEXT NOT NULL DEFAULT 'en_proceso' + CHECK (estado IN ('en_proceso', 'terminado', 'descartado')), + + FOREIGN KEY (id_proyecto) REFERENCES proyectos (id_proyecto) +); + +-- revisiones: historico de auditoria. No se borra ninguna fila de esta +-- tabla en operaciones normales; si algo se registro mal, se corrige +-- con UPDATE para conservar el rastro de que paso y cuando paso. +CREATE TABLE revisiones ( + id_revision INTEGER PRIMARY KEY AUTOINCREMENT, + id_render INTEGER NOT NULL, + comentario TEXT NOT NULL, + fecha_revision TEXT NOT NULL DEFAULT (datetime('now')), + aprobado INTEGER NOT NULL DEFAULT 0 CHECK (aprobado IN (0, 1)), + + FOREIGN KEY (id_render) REFERENCES renders (id_render) +); + +CREATE TABLE entregas ( + id_entrega INTEGER PRIMARY KEY AUTOINCREMENT, + id_proyecto INTEGER NOT NULL, + fecha_entrega TEXT NOT NULL DEFAULT (date('now')), + version TEXT NOT NULL, + + FOREIGN KEY (id_proyecto) REFERENCES proyectos (id_proyecto) +); diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/diagramas/diagrama-er.svg b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/diagramas/diagrama-er.svg new file mode 100644 index 00000000..a438d188 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/diagramas/diagrama-er.svg @@ -0,0 +1,47 @@ + + + + + clientes + id_cliente (PK) + + + proyectos + id_proyecto (PK) + id_cliente (FK) + tipo (CHECK) + + + entregas + id_entrega (PK) + id_proyecto (FK), version + + + renders + id_render (PK) + id_proyecto (FK) + estado (CHECK) + + + revisiones (historico) + id_revision (PK) + id_render (FK), aprobado (CHECK) + + + 1 : N + + + 1 : N + + + 1 : N (nunca se borra) + + + 1 : N + diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/dml/inserts.sql b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/dml/inserts.sql new file mode 100644 index 00000000..9089feff --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/dml/inserts.sql @@ -0,0 +1,59 @@ +PRAGMA foreign_keys = ON; + +-- Ejercicio 069: Diseno 3D Arquitectura +-- Datos base: 3 clientes, 4 proyectos, 9 renders, 12 revisiones, +-- 4 entregas. + +INSERT INTO clientes (nombre, telefono) VALUES + ('Manuel Estrada', '5555-8001'), + ('Alejandra Chinchilla', '5555-8002'), + ('Byron Xicay', '5555-8003'); + +INSERT INTO proyectos (id_cliente, nombre, tipo, fecha_inicio) VALUES + (1, 'Casa Vista Verde', 'residencial', '2026-07-01'), + (2, 'Torre Corporativa Central', 'comercial', '2026-07-05'), + (3, 'Escuela Nueva Esperanza', 'institucional', '2026-07-10'), + (1, 'Remodelacion Oficina', 'comercial', '2026-07-15'); + +INSERT INTO renders (id_proyecto, nombre_archivo, estado) VALUES + (1, 'casa_fachada_v1.png', 'en_proceso'), + (1, 'casa_interior_v1.png', 'terminado'), + (2, 'torre_exterior_v1.png', 'en_proceso'), + (2, 'torre_lobby_v1.png', 'terminado'), + (3, 'escuela_patio_v1.png', 'en_proceso'), + (3, 'escuela_aulas_v1.png', 'descartado'), + (4, 'oficina_recepcion_v1.png', 'terminado'), + (4, 'oficina_sala_juntas_v1.png', 'en_proceso'); + +-- Render creado por error (nombre duplicado de otro proyecto), todavia +-- sin ninguna revision asociada: es el unico caso de esta base de datos +-- donde un DELETE real es aceptable (se corrige en operaciones.sql). +INSERT INTO renders (id_proyecto, nombre_archivo, estado) VALUES + (4, 'oficina_pasillo_v1_duplicado.png', 'en_proceso'); + +-- revisiones: historico de auditoria de cada render. +INSERT INTO revisiones (id_render, comentario, aprobado) VALUES + (1, 'Falta ajustar iluminacion', 0), + (1, 'Iluminacion corregida, se aprueba', 1), + (2, 'Se aprueba sin observaciones', 1), + (3, 'Revisar proporcion de ventanas', 0), + (3, 'Ajustado, pendiente segunda revision', 0), + (4, 'Se aprueba el lobby', 1), + (5, 'Falta vegetacion en el patio', 0), + (6, 'Se descarta esta version del render', 0), + (7, 'Se aprueba la recepcion', 1), + (8, 'Revisar mobiliario de la sala', 0), + (2, 'Segunda revision de cliente, tambien aprueba', 1), + (4, 'Revision final de cliente, aprueba de nuevo', 1); + +INSERT INTO entregas (id_proyecto, fecha_entrega, version) VALUES + (1, '2026-08-01', 'v1.0'), + (2, '2026-08-05', 'v1.0'), + (4, '2026-08-10', 'v1.0'), + (1, '2026-08-15', 'v1.1'); + +-- Caso que debe fallar (queda comentado): eliminar un render que ya +-- tiene revisiones asociadas viola la FOREIGN KEY de +-- revisiones.id_render, ademas de contradecir la regla de negocio de +-- conservar el historico. +-- DELETE FROM renders WHERE id_render = 1; diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/dml/operaciones.sql b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/dml/operaciones.sql new file mode 100644 index 00000000..c09c57c6 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/dml/operaciones.sql @@ -0,0 +1,29 @@ +PRAGMA foreign_keys = ON; + +-- Ejercicio 069: Diseno 3D Arquitectura +-- Operaciones de mantenimiento sobre los datos base. + +-- 1 UPDATE de estado: el render 3 (torre_exterior) termina su proceso +-- de revision y pasa de 'en_proceso' a 'terminado'. +UPDATE renders +SET estado = 'terminado' +WHERE id_render = 3; + +-- 1 UPDATE de correccion: se corrige un comentario de revision con un +-- error de captura, SIN eliminarlo, para conservar el historico de +-- auditoria tal como pidio el cliente. +UPDATE revisiones +SET comentario = 'Ajustado segun observaciones; queda pendiente una segunda revision del cliente' +WHERE id_render = 3 AND comentario = 'Ajustado, pendiente segunda revision'; + +-- 1 DELETE controlado: se elimina el render 9 (duplicado, creado por +-- error), que todavia no tenia ninguna revision asociada. Este es el +-- unico caso del modelo donde un DELETE real es aceptable; el resto del +-- historico (revisiones) nunca se borra. +DELETE FROM renders +WHERE id_render = 9; + +-- Caso que debe fallar (queda comentado): eliminar un render que ya +-- tiene revisiones asociadas viola la FOREIGN KEY de +-- revisiones.id_render. +-- DELETE FROM renders WHERE id_render = 1; diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/dql/consultas.sql b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/dql/consultas.sql new file mode 100644 index 00000000..74d27c34 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/dql/consultas.sql @@ -0,0 +1,50 @@ +.headers on +.mode column + +-- Ejercicio 069: Diseno 3D Arquitectura +-- Consultas que responden preguntas reales del cliente. + +-- 1. Que registros principales existen: todos los renders con su +-- proyecto y cliente. +SELECT r.id_render, + pr.nombre AS proyecto, + c.nombre AS cliente, + r.nombre_archivo, + r.estado +FROM renders r +JOIN proyectos pr ON pr.id_proyecto = r.id_proyecto +JOIN clientes c ON c.id_cliente = pr.id_cliente; + +-- 2. Que registros estan en proceso, terminados o descartados. +SELECT id_render, nombre_archivo, estado +FROM renders +ORDER BY estado; + +-- 3. Que proyecto tiene mas actividad (ranking por numero de +-- revisiones, el historico de auditoria). +SELECT pr.nombre AS proyecto, + COUNT(*) AS total_revisiones +FROM revisiones rev +JOIN renders r ON r.id_render = rev.id_render +JOIN proyectos pr ON pr.id_proyecto = r.id_proyecto +GROUP BY pr.id_proyecto +ORDER BY total_revisiones DESC; + +-- 4. Revisiones ordenadas por fecha, de la mas reciente a la mas +-- antigua. +SELECT id_revision, fecha_revision, aprobado +FROM revisiones +ORDER BY fecha_revision DESC; + +-- 5. Reporte para decision de negocio: proyectos con renders aprobados +-- (al menos una revision con aprobado = 1), para saber cuales estan +-- listos para su proxima entrega (GROUP BY + HAVING). +SELECT pr.nombre AS proyecto, + COUNT(DISTINCT r.id_render) AS renders_aprobados +FROM revisiones rev +JOIN renders r ON r.id_render = rev.id_render +JOIN proyectos pr ON pr.id_proyecto = r.id_proyecto +WHERE rev.aprobado = 1 +GROUP BY pr.id_proyecto +HAVING COUNT(DISTINCT r.id_render) >= 1 +ORDER BY renders_aprobados DESC; diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/evidencias/resultados.md b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/evidencias/resultados.md new file mode 100644 index 00000000..7b1550b3 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-069/evidencias/resultados.md @@ -0,0 +1,79 @@ +# Evidencias - Ejercicio 069 + +## Comandos ejecutados + +No se conto con el binario `sqlite3` en el entorno de trabajo, por lo que +la ejecucion se valido con Python (`sqlite3`), aplicando los mismos +scripts en el mismo orden: + +```bash +sqlite3 ejercicio-069.db < ddl/schema.sql +sqlite3 ejercicio-069.db < dml/inserts.sql +sqlite3 ejercicio-069.db < dml/operaciones.sql +sqlite3 ejercicio-069.db < dql/consultas.sql +``` + +## Resultados importantes + +Conteo de datos base (despues de `inserts.sql`): + +```text +clientes -> 3 +proyectos -> 4 +renders -> 9 +revisiones -> 12 +entregas -> 4 +``` + +Caso que debe fallar - eliminar render con revisiones asociadas (`FOREIGN KEY`): + +```text +Fallo como se esperaba: FOREIGN KEY constraint failed +``` + +Despues de `operaciones.sql`: + +```text +render 3 estado: ('terminado',) -- ya no 'en_proceso' +comentario corregido, sin perder el registro de la revision original +render 9: None -- eliminado (unico DELETE valido: sin historico) +renders -> 8 +``` + +Caso que debe fallar (repetido tras `operaciones.sql`) - eliminar render con revisiones: + +```text +Fallo como se esperaba: FOREIGN KEY constraint failed +``` + +Consulta 3 (ranking de proyectos por revisiones, el historico de auditoria): + +```text +proyecto total_revisiones +Torre Corporativa Central 4 +Casa Vista Verde 4 +Remodelacion Oficina 2 +Escuela Nueva Esperanza 2 +``` + +Consulta 5 (proyectos con renders aprobados): + +```text +proyecto renders_aprobados +Casa Vista Verde 2 +Remodelacion Oficina 1 +Torre Corporativa Central 1 +``` + +## Explicacion final + +El modelo trata `revisiones` como un historico de auditoria autentico: +nunca se borra, solo se corrige con `UPDATE` cuando hubo un error de +captura, conservando siempre el rastro de que paso y cuando paso, tal +como exigio el cliente. El unico `DELETE` real permitido es sobre un +render que todavia no genero ninguna revision (un error de creacion +duplicada), y la propia `FOREIGN KEY` de `revisiones.id_render` impide +por diseno que se elimine cualquier render que ya tenga historico. Con +`JOIN`, `GROUP BY` y `HAVING` se responde exactamente lo que el estudio +necesita: que proyectos requirieron mas revisiones y cuales ya tienen +renders aprobados listos para entrega.