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
76 changes: 76 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-87/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Ejercicio 87: ORDER BY Nivel Intermedio

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

## Tema central

ORDER BY

## Descripcion del problema

Una clinica necesita ver sus citas en el orden en que realmente
importan para la operacion diaria: primero las programadas (las que
todavia hay que atender), despues las atendidas y al final las
canceladas, y solo las mas urgentes, no la lista completa.

## Tablas y relaciones

- `medicos`: catalogo de medicos.
- `pacientes`: catalogo de pacientes.
- `citas`: tabla principal. `pacientes` 1—N `citas`; `medicos` 1—N
`citas`.

## Uso de ORDER BY

En `dql/consultas.sql`:

1. Orden simple por dos columnas: `ORDER BY fecha_cita, hora_cita`
(nivel basico, punto de partida).
2. Orden por prioridad de negocio con `CASE WHEN` (nivel intermedio):
la consulta 5 ordena las citas por un orden de prioridad definido
a mano (`'programada'` = 1, `'atendida'` = 2, `'cancelada'` = 3),
en vez del orden alfabetico que darian esos mismos textos.
3. `LIMIT` combinado con `ORDER BY`: se queda solo con las 3 citas
mas urgentes segun ese orden personalizado, en vez de traer toda
la tabla.

## 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 estado, COUNT(*) FROM citas GROUP BY estado ORDER BY
horacita;` falla porque `horacita` no es el nombre real de la columna
(falta el guion bajo de `hora_cita`). Se valido con Python
(`sqlite3`): lanza `no such column: horacita`.

Se probo primero un caso distinto: ordenar una consulta agrupada por
una columna que no esta en el `GROUP BY` ni en una funcion de
agregacion. En SQLite esa combinacion **si es valida** (a diferencia
de motores mas estrictos como PostgreSQL), asi que no sirve como caso
que falla; se reemplazo por el error de escritura real.

## 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).

## Como ejecutar

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

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

-- Ejercicio 87: ORDER BY Nivel Intermedio
-- Tema central: ORDER BY
-- 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)
);
26 changes: 26 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-87/dml/inserts.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
PRAGMA foreign_keys = ON;

-- Ejercicio 87: ORDER BY Nivel Intermedio
-- 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-4501'),
('Alejandra Chinchilla', '5555-4502'),
('Byron Xicay', '5555-4503'),
('Cristina Barrios', '5555-4504'),
('Diego Paz', '5555-4505');

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-21', '08:00', 'cancelada'),
(1, 1, '2026-08-21', '09:00', 'programada'),
(3, 2, '2026-08-21', '11:00', 'programada'),
(2, 3, '2026-08-22', '10:00', 'programada');
49 changes: 49 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-87/dql/consultas.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
.headers on
.mode column

-- Ejercicio 87: ORDER BY Nivel Intermedio
-- 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: citas del medico 1.
SELECT id_cita, fecha_cita, hora_cita, estado
FROM citas
WHERE id_medico = 1;

-- 3. Consulta con ORDER BY: citas ordenadas por fecha y hora.
SELECT id_cita, fecha_cita, hora_cita
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. Validacion especifica de ORDER BY (nivel intermedio): orden por
-- prioridad de negocio en vez de orden alfabetico, usando CASE WHEN
-- dentro del ORDER BY, combinado con LIMIT para quedarse solo con las
-- 3 proximas citas mas urgentes (las programadas van primero, sin
-- importar que "atendida" y "cancelada" vengan antes alfabeticamente).
SELECT c.id_cita, p.nombre_paciente, c.fecha_cita, c.hora_cita, c.estado
FROM citas c
JOIN pacientes p ON p.id_paciente = c.id_paciente
ORDER BY
CASE c.estado
WHEN 'programada' THEN 1
WHEN 'atendida' THEN 2
WHEN 'cancelada' THEN 3
END,
c.fecha_cita,
c.hora_cita
LIMIT 3;

-- Caso comentado que debe fallar (no ser recomendable), dejar
-- comentado: escribir mal el nombre de la columna en el ORDER BY
-- (typo: "horacita" en vez de "hora_cita").
-- SELECT estado, COUNT(*) FROM citas GROUP BY estado ORDER BY horacita;
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Evidencias - Ejercicio 87

## Tema

ORDER BY

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

## Resultados

**Caso comentado verificado:**

- `SELECT estado, COUNT(*) FROM citas GROUP BY estado ORDER BY horacita;` → `no such column: horacita` (falta el guion bajo de `hora_cita`).

Nota: se probo primero un caso ordenando por una columna que no
aparece en el `SELECT` ni en el `GROUP BY` (`ORDER BY hora_cita` sobre
una consulta agrupada por `estado`), pero en SQLite eso **si es
valido** (a diferencia de otros motores mas estrictos): SQLite toma un
valor arbitrario de esa columna por cada grupo. Por eso se reemplazo
por el error de escritura real.

**5. Proximas 3 citas mas urgentes (orden por prioridad de negocio con
`CASE WHEN`, no alfabetico, y `LIMIT`):**

```text
id_cita | nombre_paciente | fecha_cita | hora_cita | estado
3 | Byron Xicay | 2026-08-20 | 11:00 | programada
4 | Cristina Barrios | 2026-08-20 | 14:00 | programada
6 | Manuel Estrada | 2026-08-21 | 09:00 | programada
```

Las citas `'programada'` aparecen primero (prioridad 1 en el `CASE
WHEN`), aunque alfabeticamente "atendida" y "cancelada" vendrian antes
que "programada". Dentro de las programadas, se ordenan por fecha y
hora, y `LIMIT 3` deja solo las 3 mas cercanas.

## Aprendizaje

`ORDER BY` no esta limitado a ordenar por el valor literal de una
columna: un `CASE WHEN` dentro del `ORDER BY` permite definir un orden
de prioridad de negocio (programada antes que atendida antes que
cancelada) que no coincide con el orden alfabetico natural del texto.
Combinado con `LIMIT`, se puede quedar solo con los primeros
resultados de ese orden personalizado (las citas mas urgentes), sin
tener que traer toda la tabla y filtrar despues en el codigo de la
aplicacion. El caso comentado confirma que SQLite es mas permisivo que
otros motores al ordenar resultados agrupados por columnas fuera del
`GROUP BY`, pero sigue exigiendo que el nombre de la columna exista de
verdad.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Solicitud SQL - Ejercicio 087: Club Futbol Sala

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

## Solicitud del cliente

Un club registra jugadores, partidos, goles, tarjetas y posiciones. El
cliente pide que el sistema permita corregir estados sin borrar
informacion importante. 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

Los goles y tarjetas de un partido ya jugado son historico oficial
del torneo: no se borran, se corrige el estado del partido con
`UPDATE` cuando algo cambia. 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

- `equipos`: catalogo de equipos del torneo.
- `jugadores`: catalogo de jugadores. `UNIQUE (id_equipo,
numero_camiseta)` impide repetir un numero de camiseta en el mismo
equipo.
- `partidos`: tabla transaccional, cada enfrentamiento entre dos
equipos.
- `goles`, `tarjetas`: historico oficial de cada partido.

## Vista SQL

`vista_resumen_partidos` (definida en
[ddl/schema.sql](ddl/schema.sql)) junta partido con los nombres de
ambos equipos, sin repetir el doble `JOIN` cada vez.

## Como se relacionan

`equipos` 1:N `jugadores`; `equipos` 1:N `partidos` (como local y como
visitante); `partidos` 1:N `goles` y `tarjetas`; `jugadores` 1:N
`goles` y `tarjetas`. El diagrama esta en
[diagramas/diagrama-er.svg](diagramas/diagrama-er.svg).

## Que datos de prueba use

3 equipos, 6 jugadores, 3 partidos (marcados `finalizado` en algun
momento), 7 goles y 4 tarjetas, incluidos un gol y una tarjeta
cargados por error para un partido que despues se descubrio que habia
que suspender. Tambien un `INSERT` comentado que reproduce el problema
de repetir un numero de camiseta y debe fallar. Detalle en
[dml/inserts.sql](dml/inserts.sql).

## Que operaciones de mantenimiento incluyo

En [dml/operaciones.sql](dml/operaciones.sql): un `UPDATE` de estado
(el partido con corte de luz pasa a `suspendido`) y dos `DELETE`
controlados que limpian el gol y la tarjeta huerfanos de ese partido,
sin tocar ningun gol ni tarjeta de un partido ya `finalizado`.

## Que consultas responden al cliente

En [dql/consultas.sql](dql/consultas.sql): el resumen de partidos
usando la vista, en que estado esta cada partido, que jugador tiene
mas goles, los goles ordenados por partido y minuto, y un reporte con
`GROUP BY` + `HAVING` de jugadores con 2 o mas goles, candidatos a
mejor jugador del torneo.

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

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