Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-82/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Ejercicio 82: SELECT Nivel Aplicado

**Nombre:** Maria Jose Montepeque
**Fecha:** 2026-08-24

## Tema central

SELECT

## Descripcion del problema

Una biblioteca tecnica presta libros y necesita saber, en cualquier
momento, cuantos ejemplares de cada libro siguen disponibles: un caso
de negocio con reporte final, propio del nivel aplicado, que combina
varias tecnicas de `SELECT` en una sola consulta.

## Tablas y relaciones

- `autores`: catalogo de autores.
- `libros`: catalogo de libros, cada uno de un autor, con su cantidad
de ejemplares totales.
- `prestamos`: tabla principal, cada prestamo de un libro.
`fecha_devolucion` queda en `NULL` mientras el prestamo sigue
activo. `autores` 1—N `libros`; `libros` 1—N `prestamos`.

## Uso de SELECT

En `dql/consultas.sql`, la consulta 5 es el reporte final del caso de
negocio:

1. Subconsulta correlacionada: por cada libro, cuenta cuantos
prestamos activos tiene (`WHERE p.id_libro = l.id_libro AND
p.fecha_devolucion IS NULL`). A diferencia de la subconsulta del
nivel intermedio (que se calculaba una sola vez), esta se vuelve a
evaluar por cada fila de `libros`.
2. Expresion calculada: `ejemplares_totales` menos esa subconsulta da
los ejemplares disponibles reales.
3. `CASE WHEN`: traduce el numero de disponibles en un estado legible
(`'disponible'` o `'agotado'`), sin que el usuario tenga que
interpretar un numero.

## Otras restricciones aplicadas

- `PRIMARY KEY` autoincremental en las 3 tablas.
- `FOREIGN KEY`: `libros.id_autor`, `prestamos.id_libro`.
- `NOT NULL` en todas las columnas obligatorias (excepto
`fecha_devolucion`, que es `NULL` a proposito mientras el prestamo
sigue activo).
- `UNIQUE`: `autores.nombre_autor`.
- `CHECK`: `libros.ejemplares_totales > 0`.
- `DEFAULT` en `prestamos.fecha_prestamo`.
- `PRAGMA foreign_keys = ON;` activado al inicio del script.

## Caso que falla / no recomendable (comentado en `dql/consultas.sql`)

`SELECT COUN(*) FROM libros;` falla porque `COUN` no es una funcion
valida (el nombre correcto es `COUNT`). Se valido con Python
(`sqlite3`): lanza `no such function: COUN`.

## 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: 3 autores, 5 libros, 7 prestamos (2 devueltos, 5
activos). Reporte final: Clean Architecture y The Art of Computer
Programming quedan `agotado`; los otros 3 libros quedan
`disponible`.

## Como ejecutar

```bash
sqlite3 ejercicio-82.db < ddl/schema.sql
sqlite3 ejercicio-82.db < dml/inserts.sql
sqlite3 ejercicio-82.db < dql/consultas.sql
```

No suba archivos `.db`, `.sqlite` ni `.sqlite3`.
33 changes: 33 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-82/ddl/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
PRAGMA foreign_keys = ON;

-- Ejercicio 82: SELECT Nivel Aplicado
-- Tema central: SELECT
-- Contexto: biblioteca tecnica, prestamos de libros.

CREATE TABLE autores (
id_autor INTEGER PRIMARY KEY AUTOINCREMENT,
nombre_autor TEXT NOT NULL UNIQUE,
especialidad TEXT NOT NULL
);

CREATE TABLE libros (
id_libro INTEGER PRIMARY KEY AUTOINCREMENT,
titulo TEXT NOT NULL,
id_autor INTEGER NOT NULL,
categoria TEXT NOT NULL,
ejemplares_totales INTEGER NOT NULL CHECK (ejemplares_totales > 0),

FOREIGN KEY (id_autor) REFERENCES autores (id_autor)
);

-- prestamos: fecha_devolucion queda NULL mientras el prestamo sigue
-- activo (el libro todavia no se devuelve).
CREATE TABLE prestamos (
id_prestamo INTEGER PRIMARY KEY AUTOINCREMENT,
id_libro INTEGER NOT NULL,
nombre_prestatario TEXT NOT NULL,
fecha_prestamo TEXT NOT NULL DEFAULT (date('now')),
fecha_devolucion TEXT,

FOREIGN KEY (id_libro) REFERENCES libros (id_libro)
);
29 changes: 29 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-82/dml/inserts.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
PRAGMA foreign_keys = ON;

-- Ejercicio 82: SELECT Nivel Aplicado
-- Datos de prueba.

INSERT INTO autores (nombre_autor, especialidad) VALUES
('Robert C. Martin', 'Ingenieria de Software'),
('Donald Knuth', 'Algoritmos'),
('Martin Fowler', 'Arquitectura de Software');

INSERT INTO libros (titulo, id_autor, categoria, ejemplares_totales) VALUES
('Clean Code', 1, 'Ingenieria', 2),
('Clean Architecture', 1, 'Arquitectura', 1),
('The Art of Computer Programming Vol. 1', 2, 'Algoritmos', 1),
('Refactoring', 3, 'Arquitectura', 3),
('Patterns of Enterprise Application Architecture', 3, 'Arquitectura', 2);

-- Prestamos ya devueltos.
INSERT INTO prestamos (id_libro, nombre_prestatario, fecha_prestamo, fecha_devolucion) VALUES
(1, 'Karla Rivas', '2026-08-01', '2026-08-10'),
(4, 'Karla Rivas', '2026-08-04', '2026-08-12');

-- Prestamos todavia activos (fecha_devolucion en NULL).
INSERT INTO prestamos (id_libro, nombre_prestatario, fecha_prestamo) VALUES
(1, 'Bryan Solis', '2026-08-05'),
(2, 'Fernanda Lopez', '2026-08-02'),
(3, 'Jorge Cifuentes', '2026-08-03'),
(4, 'Priscila Ajanel', '2026-08-06'),
(5, 'Bryan Solis', '2026-08-07');
63 changes: 63 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-82/dql/consultas.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
.headers on
.mode column

-- Ejercicio 82: SELECT Nivel Aplicado
-- Consultas de validacion.

-- 1. Mostrar todos los datos principales: prestamos con su libro y su
-- autor, con alias descriptivos.
SELECT p.id_prestamo,
l.titulo AS libro,
a.nombre_autor AS autor,
p.nombre_prestatario,
p.fecha_prestamo,
p.fecha_devolucion
FROM prestamos p
JOIN libros l ON l.id_libro = p.id_libro
JOIN autores a ON a.id_autor = l.id_autor;

-- 2. Consulta con WHERE: solo los prestamos activos (todavia no se
-- devuelve el libro).
SELECT id_prestamo, id_libro, nombre_prestatario, fecha_prestamo
FROM prestamos
WHERE fecha_devolucion IS NULL;

-- 3. Consulta con ORDER BY: prestamos ordenados por fecha.
SELECT id_prestamo, fecha_prestamo, fecha_devolucion
FROM prestamos
ORDER BY fecha_prestamo;

-- 4. Conteo o resumen: total de prestamos por libro.
SELECT id_libro, COUNT(*) AS total_prestamos
FROM prestamos
GROUP BY id_libro;

-- 5. Caso de negocio con reporte final (nivel aplicado): disponibi-
-- lidad real de cada libro, calculada con una subconsulta correla-
-- cionada (ejemplares totales menos prestamos activos de ese libro
-- especifico) y un CASE WHEN que traduce el numero a un estado
-- legible. Esto demuestra que SELECT puede combinar varias tecnicas
-- para responder una pregunta de negocio real: "que libros quedan
-- disponibles ahora mismo".
SELECT l.titulo,
l.ejemplares_totales,
l.ejemplares_totales - (
SELECT COUNT(*)
FROM prestamos p
WHERE p.id_libro = l.id_libro AND p.fecha_devolucion IS NULL
) AS ejemplares_disponibles,
CASE
WHEN l.ejemplares_totales - (
SELECT COUNT(*)
FROM prestamos p
WHERE p.id_libro = l.id_libro AND p.fecha_devolucion IS NULL
) > 0 THEN 'disponible'
ELSE 'agotado'
END AS estado_disponibilidad
FROM libros l
ORDER BY l.titulo;

-- Caso comentado que debe fallar (no ser recomendable), dejar
-- comentado: escribir mal el nombre de una funcion de agregacion
-- (COUN en vez de COUNT).
-- SELECT COUN(*) FROM libros;
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Evidencias - Ejercicio 82

## Tema

SELECT

## 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-82.db < ddl/schema.sql
sqlite3 ejercicio-82.db < dml/inserts.sql
sqlite3 ejercicio-82.db < dql/consultas.sql
```

## Resultados

**Caso comentado verificado:**

- `SELECT COUN(*) FROM libros;` → `no such function: COUN` (funcion mal escrita, la correcta es `COUNT`).

**5. Reporte final del caso de negocio (nivel aplicado): disponibilidad
real de cada libro:**

```text
titulo ejemplares_totales ejemplares_disponibles estado_disponibilidad
Clean Architecture 1 0 agotado
Clean Code 2 1 disponible
Patterns of Enterprise Application Architecture 2 1 disponible
Refactoring 3 2 disponible
The Art of Computer Programming Vol. 1 1 0 agotado
```

Verificacion manual: Clean Architecture tiene 1 ejemplar total y 1
prestamo activo (Fernanda Lopez) => 0 disponibles => agotado. The Art
of Computer Programming tiene 1 ejemplar total y 1 prestamo activo
(Jorge Cifuentes) => 0 disponibles => agotado. Los otros tres libros
tienen al menos 1 ejemplar disponible.

## Aprendizaje

La subconsulta correlacionada (`SELECT COUNT(*) FROM prestamos p
WHERE p.id_libro = l.id_libro AND p.fecha_devolucion IS NULL`) se
vuelve a ejecutar una vez por cada fila de `libros`, usando el
`id_libro` de esa fila especifica: es distinta de la subconsulta del
nivel intermedio, que se calculaba una sola vez para toda la
consulta. Combinada con `CASE WHEN`, permite traducir un numero
(ejemplares disponibles) en una palabra legible
(`'disponible'`/`'agotado'`), que es justo el tipo de reporte final
que un negocio real necesita para tomar una decision (por ejemplo,
cuales libros comprar mas ejemplares). El caso comentado recuerda que
un typo en el nombre de una funcion (`COUN` en vez de `COUNT`) tambien
hace fallar un `SELECT`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Solicitud SQL - Ejercicio 082: Academia Kickboxing

**Nombre:** Maria Jose Montepeque
**Fecha:** 2026-08-24

## Solicitud del cliente

Una academia gestiona alumnos, planes, entrenadores y asistencias. El
cliente pide saber quien compro, que compro, cuando ocurrio y cuanto
dinero representa cada movimiento. Pidio convertir esa operacion en
una base de datos que permita consultar datos, corregir estados,
registrar movimientos y sacar reportes utiles.

## Que entendi de la solicitud

A diferencia de otras solicitudes de esta serie donde esta misma
frase ("quien compro, que compro...") no encajaba directo con el
dominio, aqui si: un alumno paga un plan, en una fecha, por un monto.
Es un nivel 5 (solicitud profesional): ademas del modelo, se pide
interpretar ambiguedad, normalizar datos, documentar decisiones y
crear al menos una vista SQL. El detalle completo del analisis,
incluidas las decisiones de modelado, esta en
[analisis/requerimiento.md](analisis/requerimiento.md).

## Que tablas cree y por que

- `alumnos`: catalogo de alumnos inscritos.
- `planes`: catalogo de planes de membresia.
- `entrenadores`: catalogo de entrenadores.
- `asistencias`: tabla transaccional, cada clase a la que asiste un
alumno. `UNIQUE (id_alumno, id_entrenador, fecha_clase)` evita
registrar la misma clase dos veces.
- `pagos`: responde directamente la pregunta del cliente (quien pago,
que plan, cuando y cuanto).

## Vista SQL

`vista_pagos_alumnos` (definida en [ddl/schema.sql](ddl/schema.sql))
junta pago, alumno y plan en una sola consulta legible, respondiendo
literalmente lo que pidio el cliente sin repetir el `JOIN` cada vez.

## Como se relacionan

`alumnos` 1:N `asistencias`; `entrenadores` 1:N `asistencias`;
`alumnos` 1:N `pagos`; `planes` 1:N `pagos`. El diagrama esta en
[diagramas/diagrama-er.svg](diagramas/diagrama-er.svg).

## Que datos de prueba use

4 alumnos, 3 planes, 2 entrenadores, 7 asistencias (incluida una
cargada por error para un alumno que en realidad no asistio) y 4
pagos (2 `pendiente`, 2 `pagado`). Tambien un `INSERT` comentado que
reproduce el problema de registrar la misma asistencia dos veces y
debe fallar. Detalle en [dml/inserts.sql](dml/inserts.sql).

## Que operaciones de mantenimiento incluyo

En [dml/operaciones.sql](dml/operaciones.sql): un `DELETE` controlado
que corrige la asistencia marcada por error (solo cuando es un error
de captura confirmado) y un `UPDATE` de estado (un pago pendiente se
confirma como pagado).

## Que consultas responden al cliente

En [dql/consultas.sql](dql/consultas.sql): el resumen completo de
pagos usando la vista (responde literalmente quien, que, cuando y
cuanto), en que estado esta cada pago, que alumno tiene mas
asistencias, los pagos ordenados por fecha, y un reporte con
`GROUP BY` + `HAVING` (tambien sobre la vista) de ingresos totales por
plan, para decidir en cual invertir mas promocion.

## Evidencias

Resultados de ejecutar todo en orden, incluyendo la verificacion del
caso de duplicado y de las operaciones de mantenimiento, en
[evidencias/resultados.md](evidencias/resultados.md).

## Como ejecutar

```bash
sqlite3 ejercicio-082.db < ddl/schema.sql
sqlite3 ejercicio-082.db < dml/inserts.sql
sqlite3 ejercicio-082.db < dml/operaciones.sql
sqlite3 ejercicio-082.db < dql/consultas.sql
```

No suba archivos `.db`, `.sqlite`, `.sqlite3` ni `.dump`.
Loading
Loading