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

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

## Tema central

INSERT

## Descripcion del problema

Una clinica agenda citas relacionando pacientes con medicos. El
negocio necesita cargar medicos, pacientes y citas iniciales, tanto de
a uno como en lotes, y entender cuando conviene escribir todas las
columnas y cuando conviene dejar que `DEFAULT` complete lo que no se
indica.

## Tablas y relaciones

- `medicos`: catalogo de medicos.
- `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 INSERT

En `dml/inserts.sql`:

1. `INSERT` de una sola fila: se registra el primer medico.
2. `INSERT` multiple (varias filas en una sola sentencia
`VALUES (...), (...)`): el resto de medicos, todos los pacientes y
dos citas con estado explicito.
3. `INSERT` multiple omitiendo a proposito la columna `estado`: las
citas 3 y 4 se insertan solo con `id_paciente`, `id_medico` y
`fecha_cita`, y quedan completas con `estado = 'programada'` gracias
al `DEFAULT` de la tabla.

La consulta 5 en `dql/consultas.sql` confirma que esas dos citas no
quedaron con datos faltantes por haber omitido la columna.

## 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 de cada script.

## Casos que fallan / no recomendables (comentados en `dml/inserts.sql`)

Uno por cada restriccion, validado con Python (`sqlite3`):

- Repetir `nombre_medico` -> `UNIQUE constraint failed`.
- Apuntar a un `id_medico` que no existe -> `FOREIGN KEY constraint failed`.
- Escribir un `estado` fuera de la lista permitida -> `CHECK constraint failed`.

## 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, 4 pacientes, 4 citas (2 atendidas, 2
programadas).

## Como ejecutar

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

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

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

-- Ejercicio 71: INSERT Nivel Basico
-- Datos de prueba para validar el tema INSERT.

-- 1. INSERT de una sola fila: se registra un medico.
INSERT INTO medicos (nombre_medico, especialidad) VALUES
('Dra. Sofia Ramirez', 'Medicina General');

-- 2. INSERT multiple (varias filas en una sola sentencia): se
-- registran el resto de los medicos.
INSERT INTO medicos (nombre_medico, especialidad) VALUES
('Dr. Carlos Perez', 'Pediatria'),
('Dra. Marta Lopez', 'Traumatologia');

-- 3. INSERT multiple de pacientes, con todas las columnas explicitas.
INSERT INTO pacientes (nombre_paciente, telefono) VALUES
('Manuel Estrada', '5555-7001'),
('Alejandra Chinchilla', '5555-7002'),
('Byron Xicay', '5555-7003'),
('Cristina Barrios', '5555-7004');

-- 4. INSERT de citas con estado explicito (no depende de DEFAULT).
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');

-- 5. INSERT de citas SIN indicar estado: se omite a proposito para
-- que INSERT complete la columna con su DEFAULT ('programada'). Esto
-- demuestra que INSERT no exige escribir todas las columnas, solo las
-- que no tienen DEFAULT ni permiten NULL.
INSERT INTO citas (id_paciente, id_medico, fecha_cita) VALUES
(3, 1, '2026-08-02 08:00'),
(4, 3, '2026-08-03 11:00');

-- Casos comentados que deben fallar (no ser recomendables), dejar
-- comentados:

-- 1) Registro repetido: nombre_medico ya existe, viola el UNIQUE.
-- INSERT INTO medicos (nombre_medico, especialidad) VALUES ('Dra. Sofia Ramirez', 'Cardiologia');

-- 2) Relacion invalida: id_medico = 99 no existe, viola el FOREIGN KEY.
-- INSERT INTO citas (id_paciente, id_medico, fecha_cita) VALUES (1, 99, '2026-08-04 09:00');

-- 3) Valor fuera de rango: estado con un valor que no esta en la
-- lista permitida, viola el CHECK.
-- INSERT INTO citas (id_paciente, id_medico, fecha_cita, estado) VALUES (2, 2, '2026-08-04 10:00', 'reagendada');
37 changes: 37 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-71/dql/consultas.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.headers on
.mode column

-- Ejercicio 71: INSERT Nivel Basico
-- Consultas de validacion.

-- 1. Mostrar todos los datos principales (citas con paciente y
-- medico).
SELECT c.id_cita, p.nombre_paciente, m.nombre_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 INSERT: las citas 3 y 4 se insertaron
-- SIN indicar estado, y aun asi quedaron completas gracias al
-- DEFAULT ('programada'). Esto confirma que el INSERT multiple con
-- columnas parciales cumplio su proposito: no quedo ninguna fila con
-- datos faltantes.
SELECT id_cita, fecha_cita, estado
FROM citas
WHERE id_cita IN (3, 4);
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Evidencias - Ejercicio 71

## Tema

INSERT

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

## Resultados

Datos base tras `dml/inserts.sql`: 3 medicos, 4 pacientes, 4 citas.

**Casos comentados verificados** (descomentados y ejecutados por
separado para confirmar que cada uno falla):

- `INSERT INTO medicos (nombre_medico, ...) VALUES ('Dra. Sofia Ramirez', ...);` → `UNIQUE constraint failed: medicos.nombre_medico`.
- `INSERT INTO citas (id_paciente, id_medico, ...) VALUES (1, 99, ...);` → `FOREIGN KEY constraint failed`.
- `INSERT INTO citas (..., estado) VALUES (..., 'reagendada');` → `CHECK constraint failed: estado IN ('programada', 'atendida', 'cancelada')`.

**1. Todas las citas, con JOIN a pacientes y medicos:**

```text
id_cita | nombre_paciente | nombre_medico | fecha_cita | estado
1 | Manuel Estrada | Dra. Sofia Ramirez | 2026-08-01 09:00 | atendida
2 | Alejandra Chinchilla | Dr. Carlos Perez | 2026-08-01 10:30 | atendida
3 | Byron Xicay | Dra. Sofia Ramirez | 2026-08-02 08:00 | programada
4 | Cristina Barrios | Dra. Marta Lopez | 2026-08-03 11:00 | programada
```

**2. Citas ya atendidas:**

```text
id_cita | fecha_cita
1 | 2026-08-01 09:00
2 | 2026-08-01 10:30
```

**3. Citas ordenadas por fecha:** ver tabla completa arriba, de
2026-08-01 a 2026-08-03.

**4. Resumen: citas por estado:**

```text
estado total
atendida 2
programada 2
```

**5. Validacion especifica de INSERT: citas 3 y 4, insertadas SIN
indicar estado:**

```text
id_cita | fecha_cita | estado
3 | 2026-08-02 08:00 | programada
4 | 2026-08-03 11:00 | programada
```

Ambas quedaron completas con `estado = 'programada'` gracias al
`DEFAULT`, sin que el `INSERT` tuviera que escribir esa columna.

## Aprendizaje

`INSERT` no siempre necesita escribir todas las columnas de la tabla:
alcanza con las que no tienen `DEFAULT` ni permiten `NULL` (aqui,
`id_paciente`, `id_medico` y `fecha_cita`). Ademas, una sola sentencia
`INSERT ... VALUES` puede cargar varias filas a la vez (como los 3
medicos o los 4 pacientes de este ejercicio), lo que evita repetir la
sentencia completa fila por fila. Las restricciones de la tabla
(`UNIQUE`, `FOREIGN KEY`, `CHECK`) actuan justo en el momento del
`INSERT`: si el dato no cumple la regla, la fila nunca llega a
guardarse, como se confirmo con los tres casos comentados.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Solicitud SQL - Ejercicio 071: Battle Royale Ranking

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

## Solicitud del cliente

Una comunidad gamer registra partidas, kills, posiciones y ranking
semanal de battle royale. Hoy todo se maneja en hojas de calculo y
varias personas duplican datos sin darse cuenta. El cliente pidio
convertir esa operacion en una base de datos que permita consultar
datos, corregir estados, registrar movimientos y sacar reportes
utiles, no solo guardar texto.

## Que entendi de la solicitud

El problema central no es solo "guardar resultados", es evitar los
duplicados que hoy pasan en la hoja de calculo (el mismo jugador
cargado dos veces en la misma partida). El nivel pedido (4, reportes y
agrupaciones) exige ademas `JOIN`, `GROUP BY`, `HAVING`, totales y
ranking. El detalle completo del analisis esta en
[analisis/requerimiento.md](analisis/requerimiento.md).

## Que tablas cree y por que

- `jugadores`: catalogo de participantes de la comunidad.
- `temporadas`: catalogo de periodos de competencia.
- `partidas`: tabla transaccional, cada una dentro de una temporada.
- `estadisticas`: detalle de cada partida (kills y posicion final por
jugador). Aqui es donde se ataca el problema del cliente: un
`UNIQUE (id_partida, id_jugador)` impide que un jugador quede
cargado dos veces en la misma partida.
- `ranking`: resumen de puntos por jugador y temporada, con su propio
`UNIQUE (id_temporada, id_jugador)`. Se corrige con `UPDATE` a
medida que se juegan mas partidas, nunca se reconstruye borrando
filas.

## Como se relacionan

`temporadas` 1:N `partidas`; `partidas` 1:N `estadisticas`;
`jugadores` 1:N `estadisticas`; `temporadas` 1:N `ranking`;
`jugadores` 1:N `ranking`. El diagrama esta en
[diagramas/diagrama-er.svg](diagramas/diagrama-er.svg).

## Que datos de prueba use

5 jugadores, 1 temporada, 5 partidas (3 `jugada`, 1 `programada` y 1
que se juega y despues se anula por una caida de servidor), 16 filas
de estadisticas y el ranking inicial en 0, ademas de un `INSERT`
comentado que reproduce exactamente el problema del cliente (cargar
dos veces al mismo jugador en la misma partida) 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
(la partida anulada pasa a `cancelada`), un `DELETE` controlado que
limpia las estadisticas huerfanas de esa partida (y solo de partidas
`cancelada`, nunca de una `jugada`), y un `UPDATE` que recalcula el
ranking de la temporada a partir de las estadisticas reales.

## Que consultas responden al cliente

En [dql/consultas.sql](dql/consultas.sql): que estadisticas existen
(JOIN jugador-partida), en que estado esta cada partida, que jugador
participo en mas partidas, el ranking final de la temporada ordenado
de mayor a menor, y un reporte con `GROUP BY` + `HAVING` de que
jugadores acumularon mas kills, para decidir a quien destacar como
MVP.

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

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