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

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

## Tema central

UPDATE

## Descripcion del problema

Una bodega de dispositivos tecnologicos necesita mantener actualizado
el stock y el precio de sus productos a medida que ocurren
movimientos y cambios de mercado, sin perder el registro de cada
movimiento individual.

## Tablas y relaciones

- `categorias`: catalogo de categorias de producto.
- `productos`: catalogo de productos, con su propio `stock_actual`
como columna (a diferencia de un modelo basado solo en historial).
- `movimientos`: historial de entradas y salidas de bodega.
`categorias` 1—N `productos`; `productos` 1—N `movimientos`.

## Uso de UPDATE

En `dml/inserts.sql`:

1. `UPDATE` de una sola fila con expresion: al registrar un
reabastecimiento de Laptop Pro 14, `stock_actual = stock_actual + 5`
suma la cantidad recibida al stock existente.
2. `UPDATE` de una sola fila con expresion: al registrar una venta de
Mouse Inalambrico, `stock_actual = stock_actual - 12` resta la
cantidad vendida.
3. `UPDATE` multiple: un ajuste de precios del 10% se aplica con un
solo `UPDATE` a todos los productos de la categoria Laptops
(`WHERE id_categoria = 1`), sin listar cada `id_producto` a mano.

La consulta 5 en `dql/consultas.sql` confirma el `stock_actual` y el
`precio_unitario` finales de los 3 productos afectados.

## Otras restricciones aplicadas

- `PRIMARY KEY` autoincremental en las 3 tablas.
- `FOREIGN KEY`: `productos.id_categoria`, `movimientos.id_producto`.
- `NOT NULL` en todas las columnas obligatorias.
- `UNIQUE`: `categorias.nombre_categoria`, `productos.nombre_producto`.
- `CHECK`: `productos.precio_unitario >= 0`,
`productos.stock_actual >= 0`, `movimientos.tipo_movimiento IN (...)`,
`movimientos.cantidad > 0`.
- `DEFAULT` en `productos.stock_actual`, `movimientos.tipo_movimiento`
y `fecha_movimiento`.
- `PRAGMA foreign_keys = ON;` activado al inicio del script.

## Caso que falla / no recomendable (comentado en `dml/inserts.sql`)

`UPDATE productos SET stock_actual = stock_actual - 999 WHERE id_producto = 2;`
falla porque el resultado quedaria negativo, y eso viola el `CHECK` de
`stock_actual >= 0`. Se valido con Python (`sqlite3`): lanza
`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: Laptop Pro 14 con stock 15 y precio $9,350.00; Mouse
Inalambrico con stock 38; Laptop Air 13 con precio $6,820.00.

## Como ejecutar

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

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

-- Ejercicio 75: UPDATE Nivel Intermedio
-- Tema central: UPDATE
-- Contexto: inventario de dispositivos tecnologicos en bodega.

CREATE TABLE categorias (
id_categoria INTEGER PRIMARY KEY AUTOINCREMENT,
nombre_categoria TEXT NOT NULL UNIQUE
);

-- productos: aqui si se guarda stock_actual como columna (a
-- diferencia de un modelo basado solo en historial), justo para
-- poder practicar UPDATE sobre ella.
CREATE TABLE productos (
id_producto INTEGER PRIMARY KEY AUTOINCREMENT,
nombre_producto TEXT NOT NULL UNIQUE,
id_categoria INTEGER NOT NULL,
precio_unitario REAL NOT NULL CHECK (precio_unitario >= 0),
stock_actual INTEGER NOT NULL DEFAULT 0 CHECK (stock_actual >= 0),

FOREIGN KEY (id_categoria) REFERENCES categorias (id_categoria)
);

-- movimientos: historial de entradas y salidas de bodega, como
-- respaldo. El stock_actual de productos se corrige con UPDATE cada
-- vez que se registra un movimiento nuevo.
CREATE TABLE movimientos (
id_movimiento INTEGER PRIMARY KEY AUTOINCREMENT,
id_producto INTEGER NOT NULL,
tipo_movimiento TEXT NOT NULL DEFAULT 'entrada'
CHECK (tipo_movimiento IN ('entrada', 'salida')),
cantidad INTEGER NOT NULL CHECK (cantidad > 0),
fecha_movimiento TEXT NOT NULL DEFAULT (datetime('now')),

FOREIGN KEY (id_producto) REFERENCES productos (id_producto)
);
48 changes: 48 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-75/dml/inserts.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
PRAGMA foreign_keys = ON;

-- Ejercicio 75: UPDATE Nivel Intermedio
-- Datos de prueba y UPDATE de validacion.

INSERT INTO categorias (nombre_categoria) VALUES
('Laptops'),
('Perifericos'),
('Almacenamiento');

-- Productos con su stock inicial ya conocido de bodega.
INSERT INTO productos (nombre_producto, id_categoria, precio_unitario, stock_actual) VALUES
('Laptop Pro 14', 1, 8500.00, 10),
('Laptop Air 13', 1, 6200.00, 8),
('Mouse Inalambrico', 2, 150.00, 50),
('Teclado Mecanico', 2, 320.00, 30),
('Disco SSD 1TB', 3, 480.00, 20);

-- 1. Llega un reabastecimiento de Laptop Pro 14: se registra el
-- movimiento y, con un UPDATE de una sola fila y una expresion (no un
-- numero fijo), se suma la cantidad al stock actual.
INSERT INTO movimientos (id_producto, tipo_movimiento, cantidad) VALUES
(1, 'entrada', 5);

UPDATE productos
SET stock_actual = stock_actual + 5
WHERE id_producto = 1;

-- 2. Se vende Mouse Inalambrico: se registra el movimiento y se resta
-- del stock con la misma tecnica.
INSERT INTO movimientos (id_producto, tipo_movimiento, cantidad) VALUES
(3, 'salida', 12);

UPDATE productos
SET stock_actual = stock_actual - 12
WHERE id_producto = 3;

-- 3. UPDATE multiple: el proveedor de laptops subio precios un 10%.
-- Un solo UPDATE, con WHERE por categoria, ajusta el precio de todos
-- los productos de esa categoria a la vez (2 filas).
UPDATE productos
SET precio_unitario = ROUND(precio_unitario * 1.10, 2)
WHERE id_categoria = 1;

-- Caso comentado que debe fallar (no ser recomendable), dejar
-- comentado: restar mas unidades de las que hay en stock dejaria un
-- numero negativo, lo que viola el CHECK de stock_actual.
-- UPDATE productos SET stock_actual = stock_actual - 999 WHERE id_producto = 2;
40 changes: 40 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-75/dql/consultas.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
.headers on
.mode column

-- Ejercicio 75: UPDATE Nivel Intermedio
-- Consultas de validacion.

-- 1. Mostrar todos los datos principales (productos con su
-- categoria).
SELECT p.id_producto,
p.nombre_producto,
c.nombre_categoria,
p.precio_unitario,
p.stock_actual
FROM productos p
JOIN categorias c ON c.id_categoria = p.id_categoria;

-- 2. Consulta con WHERE: solo los movimientos de tipo salida.
SELECT id_movimiento, id_producto, cantidad
FROM movimientos
WHERE tipo_movimiento = 'salida';

-- 3. Consulta con ORDER BY: productos ordenados por stock actual, de
-- mayor a menor.
SELECT nombre_producto, stock_actual
FROM productos
ORDER BY stock_actual DESC;

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

-- 5. Validacion especifica de UPDATE: Laptop Pro 14 quedo con
-- stock_actual = 15 (broto 10, sumo 5 con el reabastecimiento) y
-- Mouse Inalambrico con stock_actual = 38 (broto 50, resto 12 por la
-- venta). Ademas, las dos laptops quedaron con el precio ya
-- actualizado un 10%.
SELECT nombre_producto, precio_unitario, stock_actual
FROM productos
WHERE id_producto IN (1, 2, 3);
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Evidencias - Ejercicio 75

## Tema

UPDATE

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

## Resultados

Estado final de `productos` tras `dml/inserts.sql` (que incluye los 3
`UPDATE` de validacion):

```text
id_producto | nombre_producto | id_categoria | precio_unitario | stock_actual
1 | Laptop Pro 14 | 1 | 9350.0 | 15
2 | Laptop Air 13 | 1 | 6820.0 | 8
3 | Mouse Inalambrico | 2 | 150.0 | 38
4 | Teclado Mecanico | 2 | 320.0 | 30
5 | Disco SSD 1TB | 3 | 480.0 | 20
```

**Caso comentado verificado:**

- `UPDATE productos SET stock_actual = stock_actual - 999 WHERE id_producto = 2;` → `CHECK constraint failed: stock_actual >= 0`.

**4. Resumen: movimientos por tipo:**

```text
tipo_movimiento total
entrada 1
salida 1
```

**5. Validacion especifica de UPDATE:**

```text
nombre_producto precio_unitario stock_actual
Laptop Pro 14 9350.0 15
Laptop Air 13 6820.0 8
Mouse Inalambrico 150.0 38
```

Laptop Pro 14: broto con `stock_actual = 10`, el `UPDATE` con
`stock_actual = stock_actual + 5` lo dejo en 15. Mouse Inalambrico:
broto con `stock_actual = 50`, el `UPDATE` con
`stock_actual = stock_actual - 12` lo dejo en 38. Las dos laptops
(Laptop Pro 14 y Laptop Air 13) subieron su precio un 10% con un solo
`UPDATE` multiple filtrado por `id_categoria = 1`
(8500.00 -> 9350.00 y 6200.00 -> 6820.00).

## Aprendizaje

`UPDATE` con una expresion (`columna = columna + n` o
`columna = columna * 1.10`) permite corregir un valor a partir de si
mismo, sin tener que calcular el resultado final antes de escribir la
sentencia. Un `WHERE` sobre una llave foranea
(`WHERE id_categoria = 1`) hace que un solo `UPDATE` afecte a todos
los productos de esa categoria a la vez, sin importar cuantos sean, lo
que es distinto a listar ids especificos con `IN (...)`. El `CHECK` de
`stock_actual >= 0` protege el modelo incluso durante un `UPDATE`: si
el nuevo valor calculado violara la restriccion, la fila no se
modifica, tal como se confirmo con el caso comentado.
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Solicitud SQL - Ejercicio 075: Track Day Hiperdeportivos

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

## Solicitud del cliente

Una pista organiza sesiones con vehiculos hiperdeportivos, pilotos y
tiempos. 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

Detras de la descripcion informal hay una operacion clara: pilotos
que corren vueltas cronometradas en sesiones, con un vehiculo
distinto en cada una, y que pagan por participar. 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

- `pilotos`: catalogo de pilotos inscritos.
- `vehiculos`: catalogo de vehiculos hiperdeportivos disponibles.
- `sesiones`: tabla transaccional, cada dia de track day.
- `tiempos`: detalle de cada sesion (tiempo de cada vuelta de cada
piloto). Aqui esta el `UNIQUE (id_sesion, id_piloto, vuelta)` que
impide cargar dos veces la misma vuelta del mismo piloto.
- `pagos`: lo que cada piloto pago por participar en una sesion.

## Como se relacionan

`sesiones` 1:N `tiempos`; `pilotos` 1:N `tiempos`; `vehiculos` 1:N
`tiempos`; `pilotos` 1:N `pagos`; `sesiones` 1:N `pagos`. El diagrama
esta en [diagramas/diagrama-er.svg](diagramas/diagrama-er.svg).

## Que datos de prueba use

3 pilotos, 3 vehiculos, 3 sesiones (marcadas `finalizada` en algun
momento), 13 tiempos (incluye uno cargado por error para una sesion
que despues se descubrio que habia que cancelar) y 6 pagos, ademas de
un `INSERT` comentado que reproduce el problema de cargar dos veces la
misma vuelta del mismo piloto 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 con falla de cronometraje pasa a `cancelada`), un `DELETE`
controlado que limpia el tiempo huerfano de esa sesion, y un `UPDATE`
multiple que confirma como `pagado` los 6 pagos pendientes de las
sesiones ya finalizadas.

## Que consultas responden al cliente

En [dql/consultas.sql](dql/consultas.sql): que tiempos existen (JOIN
piloto-vehiculo-sesion), en que estado esta cada sesion, que piloto
tiene mas vueltas registradas, los tiempos ordenados de mas rapido a
mas lento, y un reporte con `GROUP BY` + `HAVING` de que pilotos
tienen el mejor tiempo promedio, para decidir a quienes invitar al
siguiente evento.

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

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