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-88/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Ejercicio 88: ORDER BY Nivel Aplicado

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

## Tema central

ORDER BY

## Descripcion del problema

Un torneo de videojuegos necesita su tabla de posiciones oficial:
cada equipo ordenado por puntos, con la diferencia de goles como
desempate y el nombre del equipo como ultimo criterio, calculado
directamente desde el historial de partidas jugadas. Es el caso de
negocio con reporte final propio del nivel aplicado.

## Tablas y relaciones

- `equipos`: catalogo de equipos participantes.
- `jugadores`: catalogo de jugadores, cada uno de un equipo.
- `partidas`: tabla principal, cada enfrentamiento entre dos equipos.
`equipos` 1—N `jugadores`; `equipos` 1—N `partidas` (dos veces:
como local y como visitante).

## Uso de ORDER BY

La consulta 5 en `dql/consultas.sql` es la tabla de posiciones:

1. Tres subconsultas correlacionadas calculan, por cada equipo,
`puntos` (3 por victoria, 1 por empate, 0 por derrota),
`goles_favor` y `goles_contra`, contando solo partidas `'jugada'`.
2. El `ORDER BY` final usa multiples criterios de desempate, igual
que una tabla de posiciones real: `puntos DESC`, despues
`(goles_favor - goles_contra) DESC` (una expresion que combina dos
alias definidos en el propio `SELECT`), y por ultimo
`nombre_equipo ASC`.

## 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 del script.

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

Repetir la consulta 1 pero con `ORDER BY 9` falla porque esa consulta
solo tiene 6 columnas, no 9. Se valido con Python (`sqlite3`): lanza
`1st ORDER BY term out of range - should be between 1 and 6`.

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

- Tabla de posiciones final: Dragones del Norte (7 pts), Halcones del
Centro (4 pts), Tigres del Oeste (2 pts), Lobos del Sur (0 pts),
verificada a mano contra los resultados de las 5 partidas jugadas.

## Como ejecutar

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

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

-- Ejercicio 88: ORDER BY Nivel Aplicado
-- Tema central: ORDER BY
-- Contexto: torneo de videojuegos, partidas y puntajes por equipo.

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)
);
28 changes: 28 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-88/dml/inserts.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
PRAGMA foreign_keys = ON;

-- Ejercicio 88: ORDER BY Nivel Aplicado
-- Datos de prueba.

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),
('Oscar Tzul', 2),
('Melissa Ordonez', 3),
('Sergio Batz', 4);

-- Partidas jugadas.
INSERT INTO partidas (id_equipo_local, id_equipo_visitante, fecha_partida, puntaje_local, puntaje_visitante, estado) VALUES
(1, 2, '2026-08-01', 3, 1, 'jugada'),
(3, 4, '2026-08-02', 2, 2, 'jugada'),
(2, 3, '2026-08-03', 0, 1, 'jugada'),
(4, 1, '2026-08-04', 1, 1, 'jugada'),
(1, 3, '2026-08-05', 2, 0, 'jugada');

-- Partida todavia no jugada.
INSERT INTO partidas (id_equipo_local, id_equipo_visitante, fecha_partida) VALUES
(2, 4, '2026-08-08');
77 changes: 77 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-88/dql/consultas.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
.headers on
.mode column

-- Ejercicio 88: ORDER BY Nivel Aplicado
-- Consultas de validacion.

-- 1. Mostrar todos los datos principales.
SELECT p.id_partida,
eloc.nombre_equipo AS equipo_local,
evis.nombre_equipo AS equipo_visitante,
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): tabla de
-- posiciones del torneo. Cada columna (puntos, goles a favor, goles
-- en contra) se calcula con una subconsulta correlacionada sobre las
-- partidas 'jugada' de cada equipo, y el ORDER BY final usa varios
-- criterios de desempate, igual que una tabla de posiciones real:
-- primero puntos (de mas a menos), despues diferencia de goles (de
-- mas a menos), y por ultimo nombre del equipo (alfabetico) para los
-- casos que sigan empatados.
SELECT
e.nombre_equipo,
(
SELECT COALESCE(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 3
WHEN p.puntaje_local = p.puntaje_visitante THEN 1
ELSE 0
END
), 0)
FROM partidas p
WHERE p.estado = 'jugada'
AND (p.id_equipo_local = e.id_equipo OR p.id_equipo_visitante = e.id_equipo)
) AS puntos,
(
SELECT COALESCE(SUM(CASE WHEN p.id_equipo_local = e.id_equipo THEN p.puntaje_local ELSE p.puntaje_visitante END), 0)
FROM partidas p
WHERE p.estado = 'jugada'
AND (p.id_equipo_local = e.id_equipo OR p.id_equipo_visitante = e.id_equipo)
) AS goles_favor,
(
SELECT COALESCE(SUM(CASE WHEN p.id_equipo_local = e.id_equipo THEN p.puntaje_visitante ELSE p.puntaje_local END), 0)
FROM partidas p
WHERE p.estado = 'jugada'
AND (p.id_equipo_local = e.id_equipo OR p.id_equipo_visitante = e.id_equipo)
) AS goles_contra
FROM equipos e
ORDER BY puntos DESC, (goles_favor - goles_contra) DESC, e.nombre_equipo ASC;

-- Caso comentado que debe fallar (no ser recomendable), dejar
-- comentado: ordenar por la posicion de una columna que no existe en
-- el resultado (la consulta 1 solo tiene 6 columnas, no 9).
-- SELECT p.id_partida, eloc.nombre_equipo, evis.nombre_equipo, 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
-- ORDER BY 9;
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Evidencias - Ejercicio 88

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

## Resultados

**Caso comentado verificado:**

- La consulta 1 (`SELECT ... ORDER BY 9`) → `1st ORDER BY term out of range - should be between 1 and 6` (esa consulta solo tiene 6 columnas).

**5. Tabla de posiciones del torneo (reporte final, nivel aplicado):**

```text
nombre_equipo puntos goles_favor goles_contra
Dragones del Norte 7 6 2
Halcones del Centro 4 3 4
Tigres del Oeste 2 3 3
Lobos del Sur 0 1 4
```

Verificacion manual:

- Dragones del Norte: gano 2 (3-1 vs Lobos, 2-0 vs Halcones), empato 1 (1-1 vs Tigres) = 3+3+1 = 7 puntos; goles a favor 3+2+1=6, en contra 1+0+1=2.
- Halcones del Centro: empato 1 (2-2 vs Tigres), gano 1 (1-0 vs Lobos), perdio 1 (0-2 vs Dragones) = 1+3+0 = 4 puntos; GF 2+1+0=3, GC 2+0+2=4.
- Tigres del Oeste: empato 2 (2-2 vs Halcones, 1-1 vs Dragones) = 1+1 = 2 puntos; GF 2+1=3, GC 2+1=3.
- Lobos del Sur: perdio 2 (1-3 vs Dragones, 0-1 vs Halcones) = 0 puntos; GF 1+0=1, GC 3+1=4.

El orden final coincide exactamente: Dragones domina por puntos, y
como ningun equipo empata en puntos con otro, el segundo criterio
(diferencia de goles) no llego a usarse esta vez, pero esta listo
para desempatar si hiciera falta.

## Aprendizaje

El `ORDER BY` de este reporte usa tres criterios en cascada, tal como
una tabla de posiciones real: `puntos DESC` primero, despues
`(goles_favor - goles_contra) DESC`, y por ultimo `nombre_equipo ASC`
como desempate final. SQLite permite referenciar los alias definidos
en el `SELECT` (`puntos`, `goles_favor`, `goles_contra`) dentro del
`ORDER BY`, incluso combinandolos en una operacion aritmetica nueva
(`goles_favor - goles_contra`), sin tener que repetir las
subconsultas completas. El caso comentado confirma que ordenar por
posicion numerica sigue siendo fragil: la consulta 1 solo devuelve 6
columnas, y pedir `ORDER BY 9` la hace fallar de inmediato.
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Solicitud SQL - Ejercicio 088: Clinica de Tatuajes

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

## Solicitud del cliente

Un estudio de tatuajes agenda sesiones, artistas, estilos y pagos. El
cliente quiere consultar rankings, totales y casos pendientes desde
la base de datos. 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

"Rankings, totales y casos pendientes" se tradujo en tres tipos de
consulta concretos: ranking de artistas por actividad, totales de
ingresos por artista, y sesiones `'programada'` como casos
pendientes. 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

- `clientes`, `artistas`, `estilos`: catalogos.
- `sesiones`: tabla transaccional, cada cita agendada.
- `pagos`: resultado de una sesion. `UNIQUE (id_sesion)` garantiza un
solo pago oficial por sesion.

## Vista SQL

`vista_resumen_sesiones` (definida en
[ddl/schema.sql](ddl/schema.sql)) junta sesion, cliente, artista,
estilo y pago con `LEFT JOIN`, y sirve de base comun para los tres
tipos de reporte que pidio el cliente.

## Como se relacionan

`clientes` 1:N `sesiones`; `artistas` 1:N `sesiones`; `estilos` 1:N
`sesiones`; `sesiones` 1:1 `pagos`. El diagrama esta en
[diagramas/diagrama-er.svg](diagramas/diagrama-er.svg).

## Que datos de prueba use

4 clientes, 3 artistas, 3 estilos, 5 sesiones (3 `finalizada` con
pago, 1 `programada` como caso pendiente, 1 marcada `finalizada` por
error con un pago que se corrige despues) y 4 pagos. Tambien un
`INSERT` comentado que reproduce el problema de duplicar un pago para
la misma sesion 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 sesion aplazada pasa a `cancelada`) y un `DELETE` controlado que
elimina el pago invalido de esa sesion, sin tocar ningun pago de una
sesion ya `finalizada`.

## Que consultas responden al cliente

En [dql/consultas.sql](dql/consultas.sql): el resumen completo de
sesiones usando la vista, que sesiones estan pendientes, un ranking
de artistas con `ORDER BY` + `LIMIT`, las sesiones ordenadas por
fecha y duracion, y un reporte de totales con `GROUP BY` + `HAVING`
de ingresos por artista, para decidir a quien asignar mas horarios.

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

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