From 4a24eb54c2b2da73f469f16fc0480f6204fe36d2 Mon Sep 17 00:00:00 2001 From: MariaJoseMontepequeZet Date: Fri, 21 Aug 2026 16:56:41 -0600 Subject: [PATCH] feat(sql): resolver ejercicio 68 y solicitud sql 068 --- .../maria-montepeque/ejercicio-68/README.md | 80 +++++++++++++++++++ .../ejercicio-68/ddl/schema.sql | 62 ++++++++++++++ .../ejercicio-68/dml/inserts.sql | 13 +++ .../ejercicio-68/dql/consultas.sql | 36 +++++++++ .../ejercicio-68/evidencias/resultados.md | 67 ++++++++++++++++ .../solicitudes-sql/ejercicio-068/README.md | 80 +++++++++++++++++++ .../ejercicio-068/analisis/requerimiento.md | 66 +++++++++++++++ .../ejercicio-068/ddl/schema.sql | 48 +++++++++++ .../ejercicio-068/diagramas/diagrama-er.svg | 50 ++++++++++++ .../ejercicio-068/dml/inserts.sql | 47 +++++++++++ .../ejercicio-068/dml/operaciones.sql | 29 +++++++ .../ejercicio-068/dql/consultas.sql | 47 +++++++++++ .../ejercicio-068/evidencias/resultados.md | 80 +++++++++++++++++++ 13 files changed, 705 insertions(+) create mode 100644 resoluciones/maria-montepeque/ejercicio-68/README.md create mode 100644 resoluciones/maria-montepeque/ejercicio-68/ddl/schema.sql create mode 100644 resoluciones/maria-montepeque/ejercicio-68/dml/inserts.sql create mode 100644 resoluciones/maria-montepeque/ejercicio-68/dql/consultas.sql create mode 100644 resoluciones/maria-montepeque/ejercicio-68/evidencias/resultados.md create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/README.md create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/analisis/requerimiento.md create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/ddl/schema.sql create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/diagramas/diagrama-er.svg create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/dml/inserts.sql create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/dml/operaciones.sql create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/dql/consultas.sql create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/evidencias/resultados.md diff --git a/resoluciones/maria-montepeque/ejercicio-68/README.md b/resoluciones/maria-montepeque/ejercicio-68/README.md new file mode 100644 index 00000000..89c932f2 --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-68/README.md @@ -0,0 +1,80 @@ +# Ejercicio 68: DROP Nivel Basico + +**Nombre:** Maria Jose Montepeque +**Fecha:** 2026-08-21 + +## Descripcion del problema + +Una biblioteca tecnica recibio un listado de libros nuevos en una tabla +temporal de importacion, sin las restricciones finales del modelo. +Despues de migrar esos datos a la tabla definitiva `libros`, la tabla +temporal ya no sirve para nada y debe eliminarse. Lo mismo ocurre con un +indice y una vista que se usaron para un analisis puntual: una vez que +cumplieron su proposito, se eliminan sin afectar los datos reales. + +## Tabla principal + +- `libros`: tabla definitiva y permanente (titulo, categoria, + disponible). + +## Uso de DROP + +En `ddl/schema.sql`, despues de crear `libros` y migrar datos desde una +tabla temporal de importacion: + +1. `DROP TABLE libros_importacion_temporal;`: elimina la tabla temporal + una vez que sus datos ya se copiaron a `libros`. El riesgo real de + `DROP` se explica en un comentario: si se ejecutara antes de migrar + los datos, esa informacion se perderia para siempre, porque `DROP` + no se puede deshacer. +2. `CREATE INDEX idx_libros_categoria ...` seguido de + `DROP INDEX idx_libros_categoria;`: se crea un indice para un + analisis puntual y se elimina despues, porque con pocos libros no + aporta beneficio. Los datos de `libros` no se ven afectados. +3. `CREATE VIEW vista_libros_programacion ...` seguido de + `DROP VIEW vista_libros_programacion;`: se crea una vista de apoyo + para un reporte puntual y se elimina cuando ya no se va a + reutilizar. `DROP VIEW` solo borra la definicion de la vista, nunca + los datos de la tabla base. + +La consulta 5 en `dql/consultas.sql` confirma, consultando +`sqlite_master`, que los 3 objetos (tabla temporal, indice y vista) ya +no existen, mientras que los 3 libros que se migraron desde la tabla +temporal siguen disponibles en `libros`. + +## Otras restricciones aplicadas + +- `PRIMARY KEY` autoincremental. +- `NOT NULL` en todas las columnas. +- `UNIQUE`: `libros.titulo`. +- `CHECK`: `categoria IN (...)`, `disponible IN (0, 1)`. +- `DEFAULT` en `disponible`. +- `PRAGMA foreign_keys = ON;` activado al inicio del script. + +## Caso que falla / no recomendable (comentado en `ddl/schema.sql`) + +`DROP TABLE libros_importacion_temporal;` (una segunda vez) falla +porque la tabla ya no existe: se elimino antes en el mismo script. Se +valido ejecutandolo con Python (`sqlite3`): lanza +`OperationalError: no such table: libros_importacion_temporal`. Esto +demuestra por que en un script real conviene usar +`DROP TABLE IF EXISTS` cuando no se esta seguro de si el objeto ya fue +eliminado. + +## 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: 6 libros (3 migrados desde la tabla temporal, 3 + agregados directamente en `dml/inserts.sql`). + +## Como ejecutar + +```bash +sqlite3 ejercicio-68.db < ddl/schema.sql +sqlite3 ejercicio-68.db < dml/inserts.sql +sqlite3 ejercicio-68.db < dql/consultas.sql +``` diff --git a/resoluciones/maria-montepeque/ejercicio-68/ddl/schema.sql b/resoluciones/maria-montepeque/ejercicio-68/ddl/schema.sql new file mode 100644 index 00000000..6d35a41d --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-68/ddl/schema.sql @@ -0,0 +1,62 @@ +PRAGMA foreign_keys = ON; + +-- Ejercicio 68: DROP Nivel Basico +-- Tema central: DROP +-- Contexto: prestamos de libros tecnicos de una biblioteca. + +-- Tabla principal, permanente. +CREATE TABLE libros ( + id_libro INTEGER PRIMARY KEY AUTOINCREMENT, + titulo TEXT NOT NULL UNIQUE, + categoria TEXT NOT NULL + CHECK (categoria IN ('programacion', 'redes', 'bases_de_datos', 'sistemas_operativos')), + disponible INTEGER NOT NULL DEFAULT 1 CHECK (disponible IN (0, 1)) +); + +-- Tabla temporal de importacion: la biblioteca recibio un listado de +-- libros nuevos en un formato plano, sin las restricciones finales, y +-- se uso esta tabla solo para migrar los datos a la tabla definitiva. +CREATE TABLE libros_importacion_temporal ( + titulo_bruto TEXT, + categoria_bruta TEXT +); + +INSERT INTO libros_importacion_temporal (titulo_bruto, categoria_bruta) VALUES + ('Clean Code', 'programacion'), + ('Redes de Computadoras', 'redes'), + ('Designing Data-Intensive Applications', 'bases_de_datos'); + +-- Se migran los datos ya validados hacia la tabla definitiva. +INSERT INTO libros (titulo, categoria) +SELECT titulo_bruto, categoria_bruta FROM libros_importacion_temporal; + +-- DROP TABLE: la tabla de importacion ya cumplio su proposito (los +-- datos ya viven en `libros`) y se elimina para no dejar datos +-- duplicados ni confundir a quien use la base de datos despues. Este es +-- el riesgo de DROP: si se ejecutara antes de migrar los datos, esa +-- informacion se perderia para siempre. +DROP TABLE libros_importacion_temporal; + +-- Se crea un indice para acelerar busquedas por categoria... +CREATE INDEX idx_libros_categoria ON libros (categoria); + +-- ...pero la biblioteca decide que, con tan pocos libros, el indice no +-- aporta beneficio y prefiere no mantenerlo. DROP INDEX lo elimina sin +-- afectar los datos de la tabla. +DROP INDEX idx_libros_categoria; + +-- Se crea una vista de apoyo para un reporte puntual... +CREATE VIEW vista_libros_programacion AS + SELECT id_libro, titulo, disponible + FROM libros + WHERE categoria = 'programacion'; + +-- ...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 `libros` siguen intactos. +DROP VIEW vista_libros_programacion; + +-- Caso que debe fallar / no recomendable (queda comentado): intentar +-- eliminar una tabla que no existe (por ejemplo, por un error de tipeo +-- o porque ya se elimino antes) falla si no se usa IF EXISTS. +-- DROP TABLE libros_importacion_temporal; diff --git a/resoluciones/maria-montepeque/ejercicio-68/dml/inserts.sql b/resoluciones/maria-montepeque/ejercicio-68/dml/inserts.sql new file mode 100644 index 00000000..d603e2ea --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-68/dml/inserts.sql @@ -0,0 +1,13 @@ +PRAGMA foreign_keys = ON; + +-- Ejercicio 68: DROP Nivel Basico +-- Se ejecuta despues de que ddl/schema.sql migro los datos y elimino la +-- tabla temporal, el indice y la vista de apoyo. Aqui solo se agregan +-- libros nuevos directamente a la tabla definitiva. + +INSERT INTO libros (titulo, categoria) VALUES + ('Kafka: The Definitive Guide', 'bases_de_datos'), + ('Sistemas Operativos Modernos', 'sistemas_operativos'); + +INSERT INTO libros (titulo, categoria, disponible) VALUES + ('Computer Networking: A Top-Down Approach', 'redes', 0); diff --git a/resoluciones/maria-montepeque/ejercicio-68/dql/consultas.sql b/resoluciones/maria-montepeque/ejercicio-68/dql/consultas.sql new file mode 100644 index 00000000..ac9c2d54 --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-68/dql/consultas.sql @@ -0,0 +1,36 @@ +.headers on +.mode column + +-- Ejercicio 68: DROP Nivel Basico +-- Consultas de validacion. + +-- 1. Mostrar todos los datos principales. +SELECT id_libro, titulo, categoria, disponible FROM libros; + +-- 2. Consulta con WHERE. +SELECT titulo, categoria +FROM libros +WHERE disponible = 1; + +-- 3. Consulta con ORDER BY. +SELECT titulo, categoria +FROM libros +ORDER BY categoria, titulo; + +-- 4. Conteo o resumen. +SELECT categoria, COUNT(*) AS total_libros +FROM libros +GROUP BY categoria; + +-- 5. Validacion especifica de DROP: la tabla temporal, el indice y la +-- vista que se usaron y luego se eliminaron ya no existen en el +-- catalogo de la base de datos, pero los libros migrados si siguen ahi. +SELECT name, type +FROM sqlite_master +WHERE name IN ('libros_importacion_temporal', 'idx_libros_categoria', 'vista_libros_programacion'); +-- Debe devolver 0 filas: los 3 objetos se eliminaron con DROP. + +SELECT titulo, categoria +FROM libros +WHERE titulo IN ('Clean Code', 'Redes de Computadoras', 'Designing Data-Intensive Applications'); +-- Los 3 libros migrados desde la tabla temporal siguen disponibles. diff --git a/resoluciones/maria-montepeque/ejercicio-68/evidencias/resultados.md b/resoluciones/maria-montepeque/ejercicio-68/evidencias/resultados.md new file mode 100644 index 00000000..29289c1f --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-68/evidencias/resultados.md @@ -0,0 +1,67 @@ +# Evidencias - Ejercicio 68 + +## 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-68.db < ddl/schema.sql +sqlite3 ejercicio-68.db < dml/inserts.sql +sqlite3 ejercicio-68.db < dql/consultas.sql +``` + +## Resultados + +Estado justo despues de `ddl/schema.sql` (migracion + DROP de tabla, +indice y vista): + +```text +libros: [(1, 'Clean Code', 'programacion', 1), + (2, 'Redes de Computadoras', 'redes', 1), + (3, 'Designing Data-Intensive Applications', 'bases_de_datos', 1)] + +sqlite_master (tabla temporal, indice, vista): [] -- los 3 ya no existen +``` + +Caso que debe fallar (comentado en `ddl/schema.sql`): + +```text +DROP TABLE libros_importacion_temporal; -- segunda vez +Fallo como se esperaba: OperationalError: no such table: libros_importacion_temporal +``` + +Estado final (despues de `inserts.sql`), 6 libros en total: + +```text +categoria total_libros +bases_de_datos 2 +programacion 1 +redes 2 +sistemas_operativos 1 +``` + +Consulta 5 (validacion especifica de DROP): + +```text +5a. sqlite_master para los 3 objetos eliminados: sin filas +5b. libros migrados desde la tabla temporal, siguen disponibles: + ('Clean Code', 'programacion') + ('Designing Data-Intensive Applications', 'bases_de_datos') + ('Redes de Computadoras', 'redes') +``` + +## Aprendizaje + +`DROP` elimina de forma permanente una tabla, un indice o una vista, y +no se puede deshacer: por eso es indispensable migrar o respaldar los +datos importantes antes de usarlo, como se hizo aqui con la tabla +temporal de importacion. `DROP INDEX` y `DROP VIEW` son mas seguros en +el sentido de que nunca afectan los datos de la tabla base, solo +eliminan la definicion del objeto auxiliar. Consultar `sqlite_master` +es una forma directa de confirmar que un objeto realmente se elimino. diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/README.md b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/README.md new file mode 100644 index 00000000..c9c3be49 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/README.md @@ -0,0 +1,80 @@ +# Ejercicio 068: Solicitud de cliente - Escuela de Dibujo + +**Nombre:** Maria Jose Montepeque +**Fecha:** 2026-08-21 + +## Que entendi de la solicitud + +La escuela de dibujo quiere consultar rankings, totales y casos +pendientes directamente desde la base de datos. Se necesita una base de +datos que permita registrar entregas de obras, corregir su estado al +evaluarlas, y sacar reportes, como saber que alumno tiene mas actividad +o cual tiene el mejor promedio. El detalle completo del analisis esta +en [`analisis/requerimiento.md`](analisis/requerimiento.md). + +## Tablas y por que se crearon + +- `profesores`: catalogo de docentes. +- `cursos`: catalogo de cursos, cada uno de un profesor. +- `alumnos`: catalogo de estudiantes inscritos. +- `entregas`: tabla transaccional central; un alumno entrega una obra + para un curso. +- `evaluaciones`: se separa de `entregas` porque tiene su propia nota y + comentario, y no toda entrega esta evaluada todavia; relacion 1:1 + con `entregas` mediante `UNIQUE (id_entrega)`. + +## Como se relacionan + +`profesores` 1—N `cursos`; `cursos` 1—N `entregas`; `alumnos` 1—N +`entregas`; `entregas` 1—1 `evaluaciones`. + +## Datos de prueba + +2 profesores, 3 cursos, 5 alumnos, 10 entregas (con estados variados) y +7 evaluaciones. + +## Operaciones (`dml/operaciones.sql`) + +- `UPDATE`: una entrega `'pendiente'` se evalua y pasa a `'evaluada'` + (con su evaluacion correspondiente). +- `UPDATE`: se corrige la nota de una evaluacion tras una segunda + revision. +- `DELETE` controlado (con `WHERE`): se elimina una entrega + `'pendiente'` que el alumno retiro. +- Caso comentado que debe fallar: eliminar un alumno con entregas + asociadas viola la `FOREIGN KEY` de `entregas.id_alumno`. + +## Consultas que responden al cliente + +1. Todas las entregas con alumno y curso (`JOIN`). +2. Entregas filtradas por estado (`pendiente`, `evaluada`, + `rechazada`). +3. Ranking de alumnos por numero de entregas (`GROUP BY` + + `ORDER BY`). +4. Entregas ordenadas por fecha, de la mas reciente a la mas antigua. +5. Reporte de decision de negocio: promedio de notas por alumno, para + decidir a quien destacar o becar (`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: 2 profesores, 3 cursos, 5 alumnos, 10 entregas, 7 + evaluaciones. +- Tras `operaciones.sql`: 9 entregas (se elimino la retirada), 8 + evaluaciones (se agrego la de la entrega 4, se corrigio la de la + entrega 3). +- Reporte final: Alejandra Chinchilla es la alumna con mejor promedio + (93.5), seguida de Manuel Estrada (87.5). + +## Como validar + +```bash +sqlite3 ejercicio-068.db < ddl/schema.sql +sqlite3 ejercicio-068.db < dml/inserts.sql +sqlite3 ejercicio-068.db < dml/operaciones.sql +sqlite3 ejercicio-068.db < dql/consultas.sql +``` diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/analisis/requerimiento.md b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/analisis/requerimiento.md new file mode 100644 index 00000000..8c848118 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/analisis/requerimiento.md @@ -0,0 +1,66 @@ +# Analisis del requerimiento - Ejercicio 068 + +## Solicitud entendida + +Una escuela creativa de dibujo administra cursos, alumnos, entregas de +trabajos y sus evaluaciones. El cliente quiere poder consultar rankings, +totales y casos pendientes directamente desde la base de datos: por +ejemplo, que alumno tiene el mejor promedio, o cuantas entregas siguen +sin evaluar. Se necesita una base de datos que permita registrar +entregas, corregir su estado al evaluarlas, y responder esas preguntas +con reportes. + +## Entidades detectadas + +| Entidad | Por que existe | Atributos importantes | +| --- | --- | --- | +| profesores | Catalogo: imparte uno o mas cursos | nombre, especialidad | +| cursos | Catalogo: curso de dibujo impartido por un profesor | nombre (unico), nivel | +| alumnos | Catalogo: persona inscrita en la escuela | nombre, email (unico) | +| entregas | Tabla transaccional: un alumno entrega una obra para un curso | titulo_obra, fecha_entrega, estado | +| evaluaciones | Resultado de una entrega; se separa porque tiene su propia nota y comentario, y no toda entrega esta evaluada todavia | nota, comentario | + +## Relaciones detectadas + +| Relacion | Tipo | Explicacion | +| --- | --- | --- | +| profesores -> cursos | 1:N | Un profesor puede impartir varios cursos. | +| cursos -> entregas | 1:N | Un curso puede recibir muchas entregas de distintos alumnos. | +| alumnos -> entregas | 1:N | Un alumno puede hacer muchas entregas a lo largo del curso. | +| entregas -> evaluaciones | 1:1 | Cada entrega genera, a lo sumo, una evaluacion (`UNIQUE (id_entrega)`). | + +## Reglas de negocio + +- Regla 1: una entrega nace `'pendiente'` y solo puede avanzar a + `'evaluada'` o `'rechazada'` (`CHECK`). +- Regla 2: el nivel de un curso debe ser uno de los reconocidos por la + escuela (`CHECK (nivel IN ('principiante', 'intermedio', 'avanzado'))`). +- Regla 3: la nota de una evaluacion debe estar entre 0 y 100 + (`CHECK (nota BETWEEN 0 AND 100)`). +- Regla 4: el nombre de un curso y el correo de un alumno no se pueden + repetir (`UNIQUE`). +- Regla 5: cada entrega tiene como maximo una evaluacion + (`UNIQUE (id_entrega)` en `evaluaciones`). + +## Supuestos + +- El cliente no especifico si un alumno debe estar formalmente inscrito + en un curso antes de entregar; se asume, para mantener el alcance de + 5 tablas, que la relacion `alumnos` - `cursos` se infiere a partir de + las entregas registradas (no se modela una tabla de inscripciones + aparte). +- No se detallo el criterio exacto de rechazo de una entrega; se asume + que `'rechazada'` la decide el profesor al revisar la obra, sin + generar una evaluacion con nota. +- Se asume que una entrega `'pendiente'` todavia no tiene fila en + `evaluaciones`. + +## Preguntas que responde la base de datos + +1. Cuales son todas las entregas con su alumno y curso. +2. Que entregas estan pendientes, evaluadas o rechazadas. +3. Que alumno tiene mas actividad (ranking por numero de entregas). +4. Cuales son las entregas ordenadas por fecha, de la mas reciente a la + mas antigua. +5. Que alumno tiene el mejor promedio de notas (reporte para decision + de negocio: a quien destacar o becar). diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/ddl/schema.sql b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/ddl/schema.sql new file mode 100644 index 00000000..0aa43f14 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/ddl/schema.sql @@ -0,0 +1,48 @@ +PRAGMA foreign_keys = ON; + +-- Ejercicio 068: Escuela de Dibujo +-- Modelo: profesores, cursos, alumnos, entregas, evaluaciones + +CREATE TABLE profesores ( + id_profesor INTEGER PRIMARY KEY AUTOINCREMENT, + nombre TEXT NOT NULL, + especialidad TEXT NOT NULL +); + +CREATE TABLE cursos ( + id_curso INTEGER PRIMARY KEY AUTOINCREMENT, + id_profesor INTEGER NOT NULL, + nombre TEXT NOT NULL UNIQUE, + nivel TEXT NOT NULL CHECK (nivel IN ('principiante', 'intermedio', 'avanzado')), + + FOREIGN KEY (id_profesor) REFERENCES profesores (id_profesor) +); + +CREATE TABLE alumnos ( + id_alumno INTEGER PRIMARY KEY AUTOINCREMENT, + nombre TEXT NOT NULL, + email TEXT NOT NULL UNIQUE +); + +CREATE TABLE entregas ( + id_entrega INTEGER PRIMARY KEY AUTOINCREMENT, + id_alumno INTEGER NOT NULL, + id_curso INTEGER NOT NULL, + titulo_obra TEXT NOT NULL, + fecha_entrega TEXT NOT NULL DEFAULT (date('now')), + estado TEXT NOT NULL DEFAULT 'pendiente' + CHECK (estado IN ('pendiente', 'evaluada', 'rechazada')), + + FOREIGN KEY (id_alumno) REFERENCES alumnos (id_alumno), + FOREIGN KEY (id_curso) REFERENCES cursos (id_curso) +); + +CREATE TABLE evaluaciones ( + id_evaluacion INTEGER PRIMARY KEY AUTOINCREMENT, + -- UNIQUE: cada entrega tiene, a lo sumo, una evaluacion (relacion 1:1). + id_entrega INTEGER NOT NULL UNIQUE, + nota REAL NOT NULL CHECK (nota BETWEEN 0 AND 100), + comentario TEXT NOT NULL, + + FOREIGN KEY (id_entrega) REFERENCES entregas (id_entrega) +); diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/diagramas/diagrama-er.svg b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/diagramas/diagrama-er.svg new file mode 100644 index 00000000..9fc93a52 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/diagramas/diagrama-er.svg @@ -0,0 +1,50 @@ + + + + + profesores + id_profesor (PK) + nombre, especialidad + + + cursos + id_curso (PK) + id_profesor (FK) + nombre (UNIQUE), nivel (CHECK) + + + alumnos + id_alumno (PK) + email (UNIQUE) + + + entregas + id_entrega (PK) + id_alumno (FK) + id_curso (FK) + titulo_obra, fecha_entrega + estado (CHECK) + + + evaluaciones + id_evaluacion (PK) + id_entrega (FK, UNIQUE) - nota (CHECK), comentario + + + 1 : N + + + 1 : N + + + 1 : N + + + 1 : 1 + diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/dml/inserts.sql b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/dml/inserts.sql new file mode 100644 index 00000000..80ecf317 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/dml/inserts.sql @@ -0,0 +1,47 @@ +PRAGMA foreign_keys = ON; + +-- Ejercicio 068: Escuela de Dibujo +-- Datos base: 2 profesores, 3 cursos, 5 alumnos, 10 entregas, +-- 7 evaluaciones. + +INSERT INTO profesores (nombre, especialidad) VALUES + ('Prof. Ana Solares', 'Dibujo Realista'), + ('Prof. Luis Marroquin', 'Ilustracion Digital'); + +INSERT INTO cursos (id_profesor, nombre, nivel) VALUES + (1, 'Dibujo Basico', 'principiante'), + (1, 'Retrato Avanzado', 'avanzado'), + (2, 'Ilustracion Digital', 'intermedio'); + +INSERT INTO alumnos (nombre, email) VALUES + ('Manuel Estrada', 'manuel.estrada@correo.com'), + ('Alejandra Chinchilla', 'alejandra.chinchilla@correo.com'), + ('Byron Xicay', 'byron.xicay@correo.com'), + ('Cristina Barrios', 'cristina.barrios@correo.com'), + ('Douglas Pineda', 'douglas.pineda@correo.com'); + +INSERT INTO entregas (id_alumno, id_curso, titulo_obra, fecha_entrega, estado) VALUES + (1, 1, 'Bodegon a lapiz', '2026-08-01', 'evaluada'), + (2, 3, 'Personaje fantasia', '2026-08-02', 'evaluada'), + (3, 2, 'Retrato autorretrato', '2026-08-03', 'evaluada'), + (4, 1, 'Estudio de manos', '2026-08-04', 'pendiente'), + (5, 3, 'Escena urbana digital', '2026-08-05', 'evaluada'), + (1, 1, 'Naturaleza muerta', '2026-08-06', 'rechazada'), + (2, 3, 'Concepto de criatura', '2026-08-07', 'evaluada'), + (3, 2, 'Retrato de perfil', '2026-08-08', 'pendiente'), + (1, 2, 'Retrato de familiar', '2026-08-09', 'evaluada'), + (5, 1, 'Estudio de sombras', '2026-08-10', 'evaluada'); + +-- evaluaciones: solo de entregas ya 'evaluada'. +INSERT INTO evaluaciones (id_entrega, nota, comentario) VALUES + (1, 85, 'Buen manejo de sombras'), + (2, 92, 'Excelente composicion'), + (3, 78, 'Falta simetria facial'), + (5, 88, 'Buena perspectiva'), + (7, 95, 'Diseno de personaje sobresaliente'), + (9, 90, 'Gran parecido y detalle'), + (10, 70, 'Sombras poco definidas'); + +-- Caso que debe fallar (queda comentado): una segunda evaluacion para la +-- misma entrega viola UNIQUE (id_entrega) en evaluaciones. +-- INSERT INTO evaluaciones (id_entrega, nota, comentario) VALUES (1, 80, 'Segunda revision'); diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/dml/operaciones.sql b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/dml/operaciones.sql new file mode 100644 index 00000000..26c09199 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/dml/operaciones.sql @@ -0,0 +1,29 @@ +PRAGMA foreign_keys = ON; + +-- Ejercicio 068: Escuela de Dibujo +-- Operaciones de mantenimiento sobre los datos base. + +-- 1 UPDATE de estado: la entrega 4 (pendiente) se evalua y pasa a +-- 'evaluada'. +UPDATE entregas +SET estado = 'evaluada' +WHERE id_entrega = 4; + +INSERT INTO evaluaciones (id_entrega, nota, comentario) VALUES + (4, 80, 'Buen estudio de proporciones, falta detalle en sombras'); + +-- 1 UPDATE de correccion: el profesor revisa de nuevo la entrega 3 y +-- sube la nota (la primera revision fue demasiado estricta). +UPDATE evaluaciones +SET nota = 82 +WHERE id_entrega = 3; + +-- 1 DELETE controlado: se elimina la entrega 8, que el alumno retiro +-- mientras estaba 'pendiente' (no rompe integridad referencial porque +-- no existe fila en evaluaciones para id_entrega = 8). +DELETE FROM entregas +WHERE id_entrega = 8 AND estado = 'pendiente'; + +-- Caso que debe fallar (queda comentado): eliminar un alumno que tiene +-- entregas asociadas viola la FOREIGN KEY de entregas.id_alumno. +-- DELETE FROM alumnos WHERE id_alumno = 1; diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/dql/consultas.sql b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/dql/consultas.sql new file mode 100644 index 00000000..6a4cec82 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/dql/consultas.sql @@ -0,0 +1,47 @@ +.headers on +.mode column + +-- Ejercicio 068: Escuela de Dibujo +-- Consultas que responden preguntas reales del cliente. + +-- 1. Que registros principales existen: todas las entregas con alumno +-- y curso. +SELECT e.id_entrega, + a.nombre AS alumno, + c.nombre AS curso, + e.titulo_obra, + e.fecha_entrega, + e.estado +FROM entregas e +JOIN alumnos a ON a.id_alumno = e.id_alumno +JOIN cursos c ON c.id_curso = e.id_curso; + +-- 2. Que registros estan pendientes, evaluados o rechazados. +SELECT id_entrega, estado +FROM entregas +ORDER BY estado; + +-- 3. Que alumno tiene mas actividad (ranking por numero de entregas). +SELECT a.nombre AS alumno, + COUNT(*) AS total_entregas +FROM entregas e +JOIN alumnos a ON a.id_alumno = e.id_alumno +GROUP BY a.id_alumno +ORDER BY total_entregas DESC; + +-- 4. Entregas ordenadas por fecha, de la mas reciente a la mas antigua. +SELECT id_entrega, fecha_entrega, estado +FROM entregas +ORDER BY fecha_entrega DESC; + +-- 5. Reporte para decision de negocio: promedio de notas por alumno, +-- para decidir a quien destacar o becar (GROUP BY + HAVING). +SELECT a.nombre AS alumno, + COUNT(*) AS entregas_evaluadas, + ROUND(AVG(ev.nota), 1) AS promedio_nota +FROM evaluaciones ev +JOIN entregas e ON e.id_entrega = ev.id_entrega +JOIN alumnos a ON a.id_alumno = e.id_alumno +GROUP BY a.id_alumno +HAVING COUNT(*) >= 1 +ORDER BY promedio_nota DESC; diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/evidencias/resultados.md b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/evidencias/resultados.md new file mode 100644 index 00000000..e39ca065 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-068/evidencias/resultados.md @@ -0,0 +1,80 @@ +# Evidencias - Ejercicio 068 + +## 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-068.db < ddl/schema.sql +sqlite3 ejercicio-068.db < dml/inserts.sql +sqlite3 ejercicio-068.db < dml/operaciones.sql +sqlite3 ejercicio-068.db < dql/consultas.sql +``` + +## Resultados importantes + +Conteo de datos base (despues de `inserts.sql`): + +```text +profesores -> 2 +cursos -> 3 +alumnos -> 5 +entregas -> 10 +evaluaciones -> 7 +``` + +Caso que debe fallar - segunda evaluacion para la misma entrega (`UNIQUE`): + +```text +Fallo como se esperaba: UNIQUE constraint failed: evaluaciones.id_entrega +``` + +Despues de `operaciones.sql`: + +```text +entregas -> 9 (se elimino la entrega 8, retirada) +entrega 4 estado: ('evaluada',) -- ya no 'pendiente' +nota entrega3 corregida: (82.0,) -- subio de 78 a 82 +entrega 8: None -- eliminada correctamente +``` + +Caso que debe fallar - eliminar alumno con entregas asociadas (`FOREIGN KEY`): + +```text +Fallo como se esperaba: FOREIGN KEY constraint failed +``` + +Consulta 3 (ranking de alumnos por numero de entregas): + +```text +alumno total_entregas +Manuel Estrada 3 +Douglas Pineda 2 +Alejandra Chinchilla 2 +Cristina Barrios 1 +Byron Xicay 1 +``` + +Consulta 5 (promedio de notas por alumno): + +```text +alumno entregas_evaluadas promedio_nota +Alejandra Chinchilla 2 93.5 +Manuel Estrada 2 87.5 +Byron Xicay 1 82.0 +Cristina Barrios 1 80.0 +Douglas Pineda 2 79.0 +``` + +## Explicacion final + +El modelo separa catalogos (`profesores`, `cursos`, `alumnos`) de la +tabla transaccional (`entregas`) y del resultado de la evaluacion +(`evaluaciones`). Esto permite corregir el estado de una entrega y la +nota de una evaluacion sin duplicar datos de alumno o curso, eliminar +una entrega retirada sin afectar el historial de otros alumnos, y +responder con `JOIN`, `GROUP BY` y `HAVING` exactamente lo que la +escuela pidio: rankings de actividad y de promedio, para decidir a +quien destacar o becar.