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
75 changes: 75 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-85/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Ejercicio 85: WHERE Nivel Aplicado

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

## Tema central

WHERE

## Descripcion del problema

Una clinica agenda citas por fecha y necesita dos cosas del dia a dia:
la agenda pendiente de un dia especifico, ordenada por hora, y una
alerta de que pacientes cancelan seguido, para contactarlos antes de
agendarles una cita nueva: un caso de negocio con reporte final,
propio del nivel aplicado.

## Tablas y relaciones

- `medicos`: catalogo de medicos.
- `pacientes`: catalogo de pacientes.
- `citas`: tabla principal, relaciona un paciente con un medico en una
fecha y hora. `pacientes` 1—N `citas`; `medicos` 1—N `citas`.

## Uso de WHERE

En `dql/consultas.sql`:

1. Consulta 2: agenda pendiente de un dia especifico
(`WHERE fecha_cita = '2026-08-20' AND estado = 'programada'`,
ordenada por hora), el caso de negocio central del ejercicio.
2. Consulta 5 (reporte final): pacientes con 2 o mas citas
canceladas, usando `WHERE id_paciente IN (subconsulta)`, donde la
subconsulta tiene su propio `GROUP BY` y `HAVING`. Esto combina
filtrado simple con deteccion de un patron agregado, en una sola
consulta legible.

## 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_medico`, `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 `dql/consultas.sql`)

`SELECT nombre_paciente FROM pacientes p WHERE x.nombre_paciente =
'Manuel Estrada';` falla porque la tabla se declaro con el alias `p`
en el `FROM`, pero el `WHERE` intenta usar un alias `x` que nunca se
declaro. Se valido con Python (`sqlite3`): lanza
`no such column: x.nombre_paciente`.

## 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 medicos, 5 pacientes, 10 citas. Agenda pendiente
del 2026-08-20: 2 citas. Diego Paz es el unico paciente con 2 o mas
cancelaciones.

## Como ejecutar

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

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

-- Ejercicio 85: WHERE Nivel Aplicado
-- Tema central: WHERE
-- Contexto: agenda de citas medicas por fecha.

CREATE TABLE medicos (
id_medico INTEGER PRIMARY KEY AUTOINCREMENT,
nombre_medico TEXT NOT NULL UNIQUE,
especialidad TEXT NOT NULL
);

CREATE TABLE pacientes (
id_paciente INTEGER PRIMARY KEY AUTOINCREMENT,
nombre_paciente 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,
hora_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)
);
28 changes: 28 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-85/dml/inserts.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
PRAGMA foreign_keys = ON;

-- Ejercicio 85: WHERE Nivel Aplicado
-- Datos de prueba.

INSERT INTO medicos (nombre_medico, especialidad) VALUES
('Dra. Sofia Ramirez', 'Medicina General'),
('Dr. Carlos Perez', 'Pediatria'),
('Dra. Marta Lopez', 'Traumatologia');

INSERT INTO pacientes (nombre_paciente, telefono) VALUES
('Manuel Estrada', '5555-4401'),
('Alejandra Chinchilla', '5555-4402'),
('Byron Xicay', '5555-4403'),
('Cristina Barrios', '5555-4404'),
('Diego Paz', '5555-4405');

INSERT INTO citas (id_paciente, id_medico, fecha_cita, hora_cita, estado) VALUES
(1, 1, '2026-08-20', '09:00', 'atendida'),
(2, 2, '2026-08-20', '10:00', 'atendida'),
(3, 3, '2026-08-20', '11:00', 'programada'),
(4, 1, '2026-08-20', '14:00', 'programada'),
(5, 2, '2026-08-18', '09:00', 'cancelada'),
(5, 3, '2026-08-19', '10:00', 'cancelada'),
(1, 1, '2026-08-21', '09:00', 'programada'),
(3, 2, '2026-08-21', '11:00', 'programada'),
(2, 3, '2026-08-17', '15:00', 'atendida'),
(5, 1, '2026-08-22', '10:00', 'programada');
50 changes: 50 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-85/dql/consultas.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
.headers on
.mode column

-- Ejercicio 85: WHERE Nivel Aplicado
-- Consultas de validacion.

-- 1. Mostrar todos los datos principales.
SELECT c.id_cita, p.nombre_paciente, m.nombre_medico, c.fecha_cita, c.hora_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: agenda pendiente del 2026-08-20 (solo citas
-- programadas de ese dia especifico), ordenada por hora. Es el caso
-- de negocio: lo que la recepcion necesita ver esa manana.
SELECT c.id_cita, p.nombre_paciente, m.nombre_medico, c.hora_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.fecha_cita = '2026-08-20' AND c.estado = 'programada'
ORDER BY c.hora_cita;

-- 3. Consulta con ORDER BY: todas las citas ordenadas por fecha y
-- hora.
SELECT id_cita, fecha_cita, hora_cita, estado
FROM citas
ORDER BY fecha_cita, hora_cita;

-- 4. Conteo o resumen: citas por estado.
SELECT estado, COUNT(*) AS total
FROM citas
GROUP BY estado;

-- 5. Caso de negocio con reporte final (nivel aplicado): pacientes
-- con 2 o mas citas canceladas, para que la clinica los contacte
-- antes de agendarles una cita nueva. Combina WHERE con una
-- subconsulta que a su vez usa GROUP BY y HAVING.
SELECT nombre_paciente, telefono
FROM pacientes
WHERE id_paciente IN (
SELECT id_paciente
FROM citas
WHERE estado = 'cancelada'
GROUP BY id_paciente
HAVING COUNT(*) >= 2
);

-- Caso comentado que debe fallar (no ser recomendable), dejar
-- comentado: usar un alias de tabla que no se declaro en el FROM.
-- SELECT nombre_paciente FROM pacientes p WHERE x.nombre_paciente = 'Manuel Estrada';
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Evidencias - Ejercicio 85

## Tema

WHERE

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

## Resultados

**2. Agenda pendiente del 2026-08-20 (caso de negocio: lo que
recepcion necesita ver esa manana), ordenada por hora:**

```text
id_cita | nombre_paciente | nombre_medico | hora_cita
3 | Byron Xicay | Dra. Marta Lopez | 11:00
4 | Cristina Barrios | Dra. Sofia Ramirez | 14:00
```

**Caso comentado verificado:**

- `SELECT nombre_paciente FROM pacientes p WHERE x.nombre_paciente = 'Manuel Estrada';` → `no such column: x.nombre_paciente` (el alias `x` nunca se declaro en el `FROM`; la tabla se declaro como `p`).

**5. Reporte final del caso de negocio (nivel aplicado): pacientes con
2 o mas citas canceladas, para contactarlos antes de agendarles algo
nuevo:**

```text
nombre_paciente telefono
Diego Paz 5555-4405
```

Diego Paz tiene exactamente 2 citas canceladas (2026-08-18 y
2026-08-19); es el unico paciente que cumple el umbral.

## Aprendizaje

Este ejercicio combino todo lo visto en los niveles basico e
intermedio de `WHERE` en un solo caso de negocio real: filtrar por una
fecha exacta, por estado, ordenar el resultado, y usar una subconsulta
que a su vez tiene su propio `GROUP BY` y `HAVING` para detectar un
patron (pacientes que cancelan seguido). El `WHERE ... IN (subconsulta)`
permite responder una pregunta de dos pasos ("que pacientes cumplen
esta condicion agregada") sin tener que calcularla a mano fuera de
SQL. El caso comentado recuerda que un alias de tabla que no se
declaro en el `FROM` no existe para el resto de la consulta, aunque el
nombre se parezca al de la tabla real.
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Solicitud SQL - Ejercicio 085: Biblioteca Sci-Fi

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

## Solicitud del cliente

Una biblioteca especializada presta libros de ciencia ficcion y
controla devoluciones. El cliente no sabe hablar en terminos de
tablas: solo describe su operacion diaria y espera que se traduzca a
SQL. 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 versiones mas simples de este mismo caso (donde la
devolucion era solo un cambio de estado dentro de `prestamos`), aqui
se decidio separar `devoluciones` en su propia tabla, porque el
cliente quiere "registrar movimientos" y una devolucion es un
movimiento con su propio detalle (el estado fisico del libro). 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 esta en
[analisis/requerimiento.md](analisis/requerimiento.md).

## Que tablas cree y por que

- `autores`: catalogo de autores.
- `libros`: catalogo de libros, cada uno de un autor.
- `lectores`: catalogo de lectores registrados.
- `prestamos`: tabla transaccional, cada prestamo de un libro.
- `devoluciones`: resultado de un prestamo. `UNIQUE (id_prestamo)`
garantiza una sola devolucion oficial por prestamo.

## Vista SQL

`vista_resumen_prestamos` (definida en
[ddl/schema.sql](ddl/schema.sql)) junta prestamo, lector, libro,
autor y devolucion (si existe) con `LEFT JOIN`, mostrando en un solo
reporte tanto los prestamos activos como los ya devueltos.

## Como se relacionan

`autores` 1:N `libros`; `libros` 1:N `prestamos`; `lectores` 1:N
`prestamos`; `prestamos` 1:1 `devoluciones`. El diagrama esta en
[diagramas/diagrama-er.svg](diagramas/diagrama-er.svg).

## Que datos de prueba use

4 autores, 5 libros, 5 lectores, 6 prestamos y 4 devoluciones
(incluida una cargada por error en el prestamo equivocado). Tambien
un `INSERT` comentado que reproduce el problema de registrar dos
devoluciones para el mismo prestamo 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 devolucion registrada por error (solo cuando es un
error de captura confirmado) y un `UPDATE` de estado (un prestamo que
paso su fecha esperada se marca `atrasado`).

## Que consultas responden al cliente

En [dql/consultas.sql](dql/consultas.sql): el resumen completo de
prestamos usando la vista, en que estado esta cada prestamo, que
lector tiene mas prestamos, los prestamos ordenados por fecha, y un
reporte con `GROUP BY` + `HAVING` (tambien sobre la vista) de que
autor tiene mas prestamos en total, para decidir de cual comprar mas
ejemplares.

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

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