Skip to content
Merged
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
99 changes: 99 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-70/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Ejercicio 70: DROP Nivel Aplicado

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

## Tema central

DROP

## Descripcion del problema

Un torneo de videojuegos registra equipos, jugadores y partidas con su
puntaje. Los resultados de la primera jornada llegaron en una tabla
temporal de importacion que, una vez migrada a la tabla definitiva, ya
no sirve para nada. Ademas, el torneo necesita generar un reporte
oficial de posiciones (caso de negocio con validacion final, propio del
nivel aplicado) usando objetos de apoyo que se descartan despues de
usarlos.

## Tablas y relaciones

- `equipos`: catalogo de equipos participantes, tabla definitiva y
permanente.
- `jugadores`: catalogo de jugadores, cada uno ligado a un equipo.
- `partidas`: relaciona un equipo local con un equipo visitante en una
fecha, con puntaje y estado. `equipos` 1—N `jugadores`; `equipos`
1—N `partidas` (dos veces: como local y como visitante).

## Uso de DROP

En `ddl/schema.sql`, despues de crear las 3 tablas y migrar los
resultados de la primera jornada desde una tabla temporal de
importacion:

1. `DROP TABLE partidas_temporal;`: elimina la tabla temporal una vez
que sus datos ya se copiaron a `partidas`. El riesgo real de `DROP`
se explica en un comentario: ejecutarlo antes de migrar los datos
habria perdido esos resultados para siempre.

En `dql/consultas.sql` (consulta 5), el caso de negocio del nivel
aplicado:

2. `CREATE INDEX idx_partidas_estado` y
`CREATE VIEW vista_tabla_posiciones ...`: se arma un reporte oficial
de la jornada (tabla de posiciones por equipo). Se genera el reporte
consultando la vista, y una vez entregado, `DROP VIEW` y
`DROP INDEX` los eliminan porque ya cumplieron su proposito puntual.
Ninguno de los dos afecta los datos de `equipos`, `jugadores` ni
`partidas`.

La ultima parte de la consulta 5 confirma, consultando `sqlite_master`,
que la tabla temporal, la vista y el indice ya no existen, mientras que
las 5 partidas reales (con las que se armo el reporte) siguen
disponibles.

## Otras restricciones aplicadas

- `PRIMARY KEY` autoincremental en las 3 tablas.
- `FOREIGN KEY`: `jugadores.id_equipo`, `partidas.id_equipo_local`,
`partidas.id_equipo_visitante`.
- `NOT NULL` en todas las columnas obligatorias.
- `UNIQUE`: `equipos.nombre_equipo`.
- `CHECK`: `partidas.estado IN (...)`, `puntaje_local >= 0`,
`puntaje_visitante >= 0`.
- `DEFAULT` en `partidas.puntaje_local`, `puntaje_visitante` y
`estado`.
- `PRAGMA foreign_keys = ON;` activado al inicio de cada script.

## Caso que falla / no recomendable (comentado en `ddl/schema.sql`)

`DROP TABLE equipos;` falla porque `jugadores` y `partidas` todavia
tienen filas que dependen de `equipos` por `FOREIGN KEY`, y SQLite (con
`PRAGMA foreign_keys = ON`) no permite eliminar una tabla que sigue
siendo referenciada. Se valido con Python (`sqlite3`): lanza
`IntegrityError: FOREIGN KEY constraint failed`. Para poder eliminar
`equipos` habria que primero eliminar o reasignar los jugadores y
partidas que dependen de el.

## 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: 4 equipos, 6 jugadores, 5 partidas (3 jugadas, 2
programadas).
- Reporte final: Dragones del Norte lidera la tabla de posiciones con
2 partidas ganadas de 2 jugadas.

## Como ejecutar

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

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

-- Ejercicio 70: DROP Nivel Aplicado
-- Tema central: DROP
-- Contexto: torneo de videojuegos, partidas y puntajes por equipo.

-- Tablas principales, permanentes.
CREATE TABLE equipos (
id_equipo INTEGER PRIMARY KEY AUTOINCREMENT,
nombre_equipo TEXT NOT NULL UNIQUE,
region TEXT NOT NULL
);

CREATE TABLE jugadores (
id_jugador INTEGER PRIMARY KEY AUTOINCREMENT,
nombre TEXT NOT NULL,
id_equipo INTEGER NOT NULL,

FOREIGN KEY (id_equipo) REFERENCES equipos (id_equipo)
);

CREATE TABLE partidas (
id_partida INTEGER PRIMARY KEY AUTOINCREMENT,
id_equipo_local INTEGER NOT NULL,
id_equipo_visitante INTEGER NOT NULL,
fecha_partida TEXT NOT NULL,
puntaje_local INTEGER NOT NULL DEFAULT 0 CHECK (puntaje_local >= 0),
puntaje_visitante INTEGER NOT NULL DEFAULT 0 CHECK (puntaje_visitante >= 0),
estado TEXT NOT NULL DEFAULT 'programada'
CHECK (estado IN ('programada', 'jugada', 'cancelada')),

FOREIGN KEY (id_equipo_local) REFERENCES equipos (id_equipo),
FOREIGN KEY (id_equipo_visitante) REFERENCES equipos (id_equipo)
);

-- Tabla temporal de importacion: el sistema del torneo exporto los
-- resultados de la primera jornada en un formato plano, sin las
-- restricciones finales, y se usa solo para migrar esos resultados a
-- `partidas`.
CREATE TABLE partidas_temporal (
equipo_local_bruto TEXT,
equipo_visitante_bruto TEXT,
fecha_bruta TEXT,
marcador_local INTEGER,
marcador_visitante INTEGER
);

INSERT INTO equipos (nombre_equipo, region) VALUES
('Dragones del Norte', 'Norte'),
('Lobos del Sur', 'Sur'),
('Halcones del Centro', 'Centro'),
('Tigres del Oeste', 'Oeste');

INSERT INTO jugadores (nombre, id_equipo) VALUES
('Kevin Us', 1),
('Diana Perez', 1),
('Oscar Tzul', 2),
('Melissa Ordonez', 3),
('Sergio Batz', 4);

INSERT INTO partidas_temporal (equipo_local_bruto, equipo_visitante_bruto, fecha_bruta, marcador_local, marcador_visitante) VALUES
('Dragones del Norte', 'Lobos del Sur', '2026-08-01', 3, 1),
('Halcones del Centro', 'Tigres del Oeste', '2026-08-02', 2, 2);

-- Migracion: se traduce cada nombre bruto a su id_equipo real y el
-- resultado queda como partida ya jugada.
INSERT INTO partidas (id_equipo_local, id_equipo_visitante, fecha_partida, puntaje_local, puntaje_visitante, estado)
SELECT
eloc.id_equipo,
evis.id_equipo,
pt.fecha_bruta,
pt.marcador_local,
pt.marcador_visitante,
'jugada'
FROM partidas_temporal pt
JOIN equipos eloc ON eloc.nombre_equipo = pt.equipo_local_bruto
JOIN equipos evis ON evis.nombre_equipo = pt.equipo_visitante_bruto;

-- Partidas de la siguiente jornada, cargadas directo en la tabla
-- definitiva (todavia no se jugaron).
INSERT INTO partidas (id_equipo_local, id_equipo_visitante, fecha_partida, estado) VALUES
(2, 3, '2026-08-08', 'programada'),
(4, 1, '2026-08-08', 'programada');

-- DROP TABLE: la tabla de importacion ya cumplio su proposito (los
-- resultados ya viven en `partidas`) y se elimina para no dejar datos
-- duplicados. Este es el riesgo de DROP: si se ejecutara antes de
-- migrar los datos, esos resultados se perderian para siempre.
DROP TABLE partidas_temporal;

-- El ciclo completo crear -> usar para el reporte oficial -> eliminar
-- de un indice y una vista de apoyo (tabla de posiciones) se hace en
-- dql/consultas.sql (consulta 5), despues de que ya existen datos
-- suficientes para que el reporte tenga sentido.

-- Caso que debe fallar / no recomendable (queda comentado): intentar
-- eliminar una tabla que todavia esta referenciada por FOREIGN KEY
-- desde otra tabla con filas. SQLite, con PRAGMA foreign_keys = ON, no
-- permite este DROP mientras existan jugadores o partidas que dependan
-- de equipos: hay que eliminar o reasignar esas filas primero.
-- DROP TABLE equipos;
13 changes: 13 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-70/dml/inserts.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
PRAGMA foreign_keys = ON;

-- Ejercicio 70: DROP Nivel Aplicado
-- Se ejecuta despues de que ddl/schema.sql migro los resultados de la
-- primera jornada y elimino la tabla temporal. Aqui solo se agregan
-- registros nuevos directamente a las tablas definitivas.

INSERT INTO jugadores (nombre, id_equipo) VALUES
('Paola Coy', 2);

-- Resultado real de una partida que estaba programada: ya se jugo.
INSERT INTO partidas (id_equipo_local, id_equipo_visitante, fecha_partida, puntaje_local, puntaje_visitante, estado) VALUES
(1, 3, '2026-08-15', 4, 2, 'jugada');
79 changes: 79 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-70/dql/consultas.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
.headers on
.mode column

-- Ejercicio 70: DROP Nivel Aplicado
-- Consultas de validacion.

-- 1. Mostrar todos los datos principales (partidas con nombre de
-- equipo local y visitante).
SELECT p.id_partida,
eloc.nombre_equipo AS equipo_local,
evis.nombre_equipo AS equipo_visitante,
p.fecha_partida,
p.puntaje_local,
p.puntaje_visitante,
p.estado
FROM partidas p
JOIN equipos eloc ON eloc.id_equipo = p.id_equipo_local
JOIN equipos evis ON evis.id_equipo = p.id_equipo_visitante;

-- 2. Consulta con WHERE: partidas ya jugadas.
SELECT id_partida, fecha_partida, puntaje_local, puntaje_visitante
FROM partidas
WHERE estado = 'jugada';

-- 3. Consulta con ORDER BY: partidas ordenadas por fecha.
SELECT id_partida, fecha_partida, estado
FROM partidas
ORDER BY fecha_partida;

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

-- 5. Caso de negocio con reporte final (nivel aplicado): se crea un
-- indice de apoyo y una vista de tabla de posiciones, se usan para
-- generar el reporte oficial de la jornada, y se eliminan enseguida
-- porque solo servian para esa validacion puntual.
CREATE INDEX idx_partidas_estado ON partidas (estado);

CREATE VIEW vista_tabla_posiciones AS
SELECT
e.id_equipo,
e.nombre_equipo,
COUNT(*) AS partidas_jugadas,
SUM(
CASE
WHEN (p.id_equipo_local = e.id_equipo AND p.puntaje_local > p.puntaje_visitante)
OR (p.id_equipo_visitante = e.id_equipo AND p.puntaje_visitante > p.puntaje_local)
THEN 1 ELSE 0
END
) AS partidas_ganadas
FROM equipos e
JOIN partidas p
ON (p.id_equipo_local = e.id_equipo OR p.id_equipo_visitante = e.id_equipo)
AND p.estado = 'jugada'
GROUP BY e.id_equipo, e.nombre_equipo;

-- Reporte oficial de la jornada: tabla de posiciones.
SELECT nombre_equipo, partidas_jugadas, partidas_ganadas
FROM vista_tabla_posiciones
ORDER BY partidas_ganadas DESC, nombre_equipo;

-- Una vez entregado el reporte, se eliminan la vista y el indice: ya
-- cumplieron su proposito puntual.
DROP VIEW vista_tabla_posiciones;
DROP INDEX idx_partidas_estado;

-- Validacion especifica de DROP: ni la tabla temporal de la migracion
-- (eliminada en ddl/schema.sql) ni la vista/indice del reporte (recien
-- eliminados) existen ya en el catalogo, pero los datos de partidas y
-- equipos que se usaron para generarlos siguen intactos.
SELECT name, type
FROM sqlite_master
WHERE name IN ('partidas_temporal', 'vista_tabla_posiciones', 'idx_partidas_estado');
-- Debe devolver 0 filas: los 3 objetos se eliminaron con DROP.

SELECT COUNT(*) AS total_partidas FROM partidas;
-- Las partidas reales (con las que se armo el reporte) siguen ahi.
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Evidencias - Ejercicio 70

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

## Resultados

Estado justo despues de `ddl/schema.sql` (migracion de la primera
jornada desde `partidas_temporal` + `DROP TABLE`):

```text
equipos: 4 registros (Dragones del Norte, Lobos del Sur, Halcones del Centro, Tigres del Oeste)
partidas: 4 (2 jugadas migradas, 2 programadas)
sqlite_master (partidas_temporal): [] -- ya no existe
```

Caso que debe fallar (comentado en `ddl/schema.sql`):

```text
DROP TABLE equipos;
Fallo como se esperaba: FOREIGN KEY constraint failed
```

Estado final (despues de `dml/inserts.sql`), 5 partidas en total:

```text
estado total
jugada 3
programada 2
```

Reporte oficial de la jornada (consulta 5, con la vista
`vista_tabla_posiciones` antes de eliminarla):

```text
nombre_equipo partidas_jugadas partidas_ganadas
Dragones del Norte 2 2
Halcones del Centro 2 0
Lobos del Sur 1 0
Tigres del Oeste 1 0
```

Validacion especifica de DROP (consulta 5, despues de `DROP VIEW` y
`DROP INDEX`):

```text
5a. sqlite_master para partidas_temporal, vista_tabla_posiciones e
idx_partidas_estado: sin filas -- los 3 objetos se eliminaron.
5b. total_partidas: 5 -- los datos reales con los que se armo el
reporte siguen intactos.
```

## Aprendizaje

Ademas de lo visto en el nivel intermedio (migrar y eliminar una tabla
temporal, o crear y eliminar una vista de apoyo), este ejercicio de
nivel aplicado agrego un caso de negocio completo: un indice y una
vista se crean, se usan para generar un reporte oficial (la tabla de
posiciones del torneo) y se eliminan enseguida porque ya cumplieron su
proposito puntual. `DROP` no es solo "borrar algo que sobra": tambien
es parte normal del ciclo de vida de un objeto de apoyo que se crea
para una tarea especifica y se descarta una vez terminada, sin tocar
los datos reales (`equipos`, `jugadores`, `partidas`) que ese objeto
consultaba. El caso comentado (`DROP TABLE equipos`) confirma que las
`FOREIGN KEY` protegen a las tablas permanentes de un DROP accidental
mientras tengan filas dependientes.
Loading
Loading