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

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

## Descripcion del problema

Un sistema de ventas de cafeteria necesita generar automaticamente el id
de clientes, productos y ventas, sin que la aplicacion tenga que
calcular el siguiente numero disponible, incluso cuando una venta se
elimina despues de registrada.

## Tablas y relaciones

- `clientes`: catalogo de clientes (nombre, telefono).
- `productos`: catalogo de productos de la cafeteria (nombre, precio).
- `ventas`: venta de un producto a un cliente (cantidad, fecha).
`clientes` 1—N `ventas`; `productos` 1—N `ventas`.

## Uso de AUTO_INCREMENT

En SQLite el equivalente de `AUTO_INCREMENT` es
`INTEGER PRIMARY KEY AUTOINCREMENT`. Se aplico en las 3 tablas
(`clientes.id_cliente`, `productos.id_producto`, `ventas.id_venta`):
ningun `INSERT` indica el id, SQLite lo asigna solo y de forma creciente.

Para demostrar que el id nunca se reutiliza, incluso en la tabla que
tiene relaciones con otras dos tablas:

1. Se insertan 5 ventas (ids 1 a 5).
2. Se elimina la venta con `id_venta = 3` (Byron Xicay, Pastel de
Chocolate).
3. Se inserta una venta nueva: recibe el `id_venta = 6`, **no** el 3 que
quedo libre. `AUTOINCREMENT` usa la tabla interna `sqlite_sequence`
para recordar el maximo historico de cada tabla, en vez de basarse
solo en `MAX(id)`.

## Otras restricciones aplicadas

- `PRIMARY KEY` autoincremental en las 3 tablas.
- `FOREIGN KEY`: `ventas.id_cliente`, `ventas.id_producto`.
- `NOT NULL` en todos los campos obligatorios.
- `UNIQUE`: `clientes.telefono`, `productos.nombre`.
- `CHECK`: `productos.precio > 0`, `ventas.cantidad > 0`.
- `PRAGMA foreign_keys = ON;` activado al inicio del script.

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

`INSERT INTO ventas (id_cliente, id_producto, cantidad) VALUES (1, 999, 1);`
falla porque el `id_producto = 999` no existe (viola la `FOREIGN KEY`).
Se valido ejecutandolo con Python (`sqlite3`): lanza
`IntegrityError: FOREIGN KEY 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 clientes, 3 productos, 5 ventas (ids 1, 2, 4, 5, 6 --
el 3 nunca se reutilizo).

## Como ejecutar

```bash
sqlite3 ejercicio-63.db < ddl/schema.sql
sqlite3 ejercicio-63.db < dml/inserts.sql
sqlite3 ejercicio-63.db < dql/consultas.sql
```
32 changes: 32 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-63/ddl/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
PRAGMA foreign_keys = ON;

-- Ejercicio 63: AUTO_INCREMENT Nivel Intermedio
-- Tema central: AUTO_INCREMENT
-- Contexto: ventas diarias de una cafeteria (clientes, productos, ventas).

-- clientes: id_cliente generado solo con AUTOINCREMENT.
CREATE TABLE clientes (
id_cliente INTEGER PRIMARY KEY AUTOINCREMENT,
nombre TEXT NOT NULL,
telefono TEXT NOT NULL UNIQUE
);

-- productos: id_producto generado solo con AUTOINCREMENT.
CREATE TABLE productos (
id_producto INTEGER PRIMARY KEY AUTOINCREMENT,
nombre TEXT NOT NULL UNIQUE,
precio REAL NOT NULL CHECK (precio > 0)
);

-- ventas: id_venta generado solo con AUTOINCREMENT; relaciona clientes
-- y productos.
CREATE TABLE ventas (
id_venta INTEGER PRIMARY KEY AUTOINCREMENT,
id_cliente INTEGER NOT NULL,
id_producto INTEGER NOT NULL,
cantidad INTEGER NOT NULL DEFAULT 1 CHECK (cantidad > 0),
fecha_venta TEXT NOT NULL DEFAULT (datetime('now')),

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

-- Ejercicio 63: AUTO_INCREMENT Nivel Intermedio
-- Datos de prueba: 3 clientes, 3 productos, ventas relacionadas.
-- Ningun INSERT indica el id: lo genera AUTOINCREMENT en las 3 tablas.

INSERT INTO clientes (nombre, telefono) VALUES
('Manuel Estrada', '5555-2001'),
('Alejandra Chinchilla', '5555-2002'),
('Byron Xicay', '5555-2003');

INSERT INTO productos (nombre, precio) VALUES
('Cafe Americano', 15.00),
('Capuchino', 18.50),
('Pastel de Chocolate', 22.00);

INSERT INTO ventas (id_cliente, id_producto, cantidad) VALUES
(1, 1, 2),
(2, 2, 1),
(3, 3, 1),
(1, 2, 1),
(2, 1, 3);
-- ids esperados 1..5, asignados automaticamente por AUTOINCREMENT.

-- Se elimina la venta 3 (Byron Xicay, Pastel de Chocolate) para
-- demostrar que AUTOINCREMENT nunca reutiliza un id ya usado.
DELETE FROM ventas WHERE id_venta = 3;

-- Nueva venta: SQLite le asigna el id 6, NO el id 3 que quedo libre.
INSERT INTO ventas (id_cliente, id_producto, cantidad) VALUES
(3, 3, 2);

-- Caso que debe fallar (queda comentado): referenciar un producto que no
-- existe viola la FOREIGN KEY de ventas.id_producto.
-- INSERT INTO ventas (id_cliente, id_producto, cantidad) VALUES (1, 999, 1);
37 changes: 37 additions & 0 deletions resoluciones/maria-montepeque/ejercicio-63/dql/consultas.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.headers on
.mode column

-- Ejercicio 63: AUTO_INCREMENT Nivel Intermedio
-- Consultas de validacion.

-- 1. Mostrar todos los datos principales (ventas con cliente y producto).
SELECT v.id_venta, c.nombre AS cliente, p.nombre AS producto,
v.cantidad, v.fecha_venta
FROM ventas v
JOIN clientes c ON c.id_cliente = v.id_cliente
JOIN productos p ON p.id_producto = v.id_producto;

-- 2. Consulta con WHERE: ventas de mas de una unidad.
SELECT id_venta, id_cliente, id_producto, cantidad
FROM ventas
WHERE cantidad > 1;

-- 3. Consulta con ORDER BY: ventas ordenadas por id descendente.
SELECT id_venta, fecha_venta
FROM ventas
ORDER BY id_venta DESC;

-- 4. Conteo o resumen: total de ventas registradas.
SELECT COUNT(*) AS total_ventas FROM ventas;

-- 5. Validacion especifica de AUTO_INCREMENT: el id 3 (venta eliminada)
-- nunca vuelve a aparecer, y la ultima venta insertada recibio un id
-- nuevo (6), no el que quedo libre.
SELECT id_venta, id_cliente, id_producto
FROM ventas
ORDER BY id_venta;

SELECT id_venta
FROM ventas
WHERE id_venta = 3;
-- Debe devolver 0 filas: el id 3 quedo libre pero AUTOINCREMENT no lo reutilizo.
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Evidencias - Ejercicio 63

## Tema

AUTO_INCREMENT

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

## Resultados

Conteo final de datos:

```text
clientes -> 3
productos -> 3
ventas -> 5
```

Caso que debe fallar (comentado en `dml/inserts.sql`):

```text
INSERT INTO ventas (id_cliente, id_producto, cantidad) VALUES (1, 999, 1);
Fallo como se esperaba: FOREIGN KEY constraint failed
```

Consulta 5 (validacion especifica de AUTO_INCREMENT):

```text
5a. ventas finales en orden
(1, 1, 1)
(2, 2, 2)
(4, 1, 2)
(5, 2, 1)
(6, 3, 3) -- ultima venta insertada, recibio id 6

5b. buscar id_venta = 3 (eliminada antes)
(sin filas) -- confirma que AUTOINCREMENT no reutilizo el id 3
```

## Aprendizaje

`INTEGER PRIMARY KEY AUTOINCREMENT` garantiza que cada nueva fila reciba
un id mayor a cualquiera usado antes en esa tabla, aunque se eliminen
filas intermedias. Esto es especialmente importante en una tabla con
relaciones (`ventas` referenciando `clientes` y `productos`): si un id
eliminado se reutilizara, podria generar confusion al mezclar historicos
de ventas antiguas con ventas nuevas que compartieran el mismo
identificador.
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Ejercicio 063: Solicitud de cliente - Clinica de Tatuajes

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

## Que entendi de la solicitud

El estudio de tatuajes quiere evitar registros incompletos porque eso le
impide hacer reportes confiables. Necesita una base de datos que permita
consultar sesiones, corregir su estado, registrar pagos y sacar
reportes, como saber que artista tiene mas actividad o cuanto se
factura por estilo de tatuaje. El detalle completo del analisis esta en
[`analisis/requerimiento.md`](analisis/requerimiento.md).

## Tablas y por que se crearon

- `clientes`: catalogo de clientes (se repite en muchas sesiones).
- `artistas`: catalogo de tatuadores (se repite en muchas sesiones).
- `estilos`: catalogo de estilos de tatuaje (se repite en muchas
sesiones).
- `sesiones`: tabla transaccional central; relaciona cliente, artista y
estilo, con duracion, fecha y estado. `cliente`, `artista` y `estilo`
son `NOT NULL` a proposito, para que ninguna sesion quede incompleta.
- `pagos`: se separa de `sesiones` porque tiene su propio ciclo de vida
(pendiente, pagado, reembolsado) y metodo de pago; relacion 1:1 con
`sesiones` mediante `UNIQUE (id_sesion)`.

## Como se relacionan

`clientes` 1—N `sesiones`, `artistas` 1—N `sesiones`, `estilos` 1—N
`sesiones`, `sesiones` 1—1 `pagos`.

## Datos de prueba

5 clientes, 3 artistas, 4 estilos, 10 sesiones (con estados variados) y
6 pagos.

## Operaciones (`dml/operaciones.sql`)

- `UPDATE`: una sesion agendada se realiza y pasa a `'completada'`.
- `UPDATE`: se confirma como `'pagado'` un pago que estaba pendiente.
- `DELETE` controlado (con `WHERE`): se elimina una sesion `'cancelada'`
que nunca genero pago.
- Caso comentado que debe fallar: eliminar un artista con sesiones
asociadas viola la `FOREIGN KEY` de `sesiones.id_artista`.

## Consultas que responden al cliente

1. Todas las sesiones con cliente, artista y estilo (`JOIN`).
2. Sesiones filtradas por estado (`agendada`, `completada`,
`cancelada`).
3. Ranking de artistas por sesiones completadas (`GROUP BY` +
`ORDER BY`).
4. Sesiones ordenadas por fecha, de la mas reciente a la mas antigua.
5. Reporte de decision de negocio: facturacion por estilo, solo pagos
ya `'pagado'`, filtrando los que superan Q300 (`GROUP BY` +
`HAVING`).

## Evidencias de ejecucion

Scripts validados en orden (`ddl` -> `inserts` -> `operaciones` ->
`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 base: 5 clientes, 3 artistas, 4 estilos, 10 sesiones, 6 pagos.
- Tras `operaciones.sql`: 9 sesiones (se elimino la cancelada sin pago).
- Reporte final: "Realismo" es el estilo con mayor facturacion
(Q500.00), seguido de "Tradicional Japones" (Q480.00).

## Como validar

```bash
sqlite3 ejercicio-063.db < ddl/schema.sql
sqlite3 ejercicio-063.db < dml/inserts.sql
sqlite3 ejercicio-063.db < dml/operaciones.sql
sqlite3 ejercicio-063.db < dql/consultas.sql
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Analisis del requerimiento - Ejercicio 063

## Solicitud entendida

Un estudio de tatuajes agenda sesiones, artistas, estilos y pagos, y
quiere evitar registros incompletos porque despues no puede hacer
reportes confiables. Necesita una base de datos que permita consultar
datos, corregir estados de una sesion, registrar pagos y sacar reportes
utiles, por ejemplo saber que artista tiene mas sesiones completadas o
cuanto se factura por estilo.

## Entidades detectadas

| Entidad | Por que existe | Atributos importantes |
| --- | --- | --- |
| clientes | Persona que agenda la sesion; se repite en varias sesiones | nombre, telefono (unico) |
| artistas | Tatuador que realiza la sesion; se repite en varias sesiones | nombre, especialidad |
| estilos | Catalogo de estilos de tatuaje; se repite en varias sesiones | nombre (unico) |
| sesiones | Tabla transaccional central: relaciona cliente, artista y estilo en una fecha, con duracion y estado | fecha_sesion, duracion_horas, estado |
| pagos | Movimiento de dinero asociado a una sesion; se separa porque tiene su propio ciclo de vida (pendiente, pagado, reembolsado) y metodo de pago | monto, metodo_pago, estado_pago |

## Relaciones detectadas

| Relacion | Tipo | Explicacion |
| --- | --- | --- |
| clientes -> sesiones | 1:N | Un cliente puede agendar muchas sesiones, cada sesion es de un solo cliente. |
| artistas -> sesiones | 1:N | Un artista puede tener muchas sesiones, cada sesion tiene un solo artista. |
| estilos -> sesiones | 1:N | Un estilo puede aparecer en muchas sesiones, cada sesion es de un solo estilo. |
| sesiones -> pagos | 1:1 | Cada sesion genera un unico registro de pago (`UNIQUE (id_sesion)`). |

## Reglas de negocio

- Regla 1: para evitar registros incompletos, `cliente`, `artista` y
`estilo` son obligatorios (`NOT NULL`) en toda sesion; no se permite
crear una sesion "a medias".
- Regla 2: una sesion nace `'agendada'` y solo puede avanzar a
`'completada'` o `'cancelada'` (`CHECK`).
- Regla 3: la duracion de una sesion debe ser mayor a cero
(`CHECK (duracion_horas > 0)`).
- Regla 4: cada sesion tiene como maximo un pago
(`UNIQUE (id_sesion)` en `pagos`), y el monto debe ser mayor a cero.
- Regla 5: el telefono del cliente no se puede repetir (`UNIQUE`), para
evitar duplicar el mismo cliente con datos distintos.

## Supuestos

- El cliente (dueno del estudio) no especifico si un artista puede
manejar mas de un estilo; se asume que si, por eso `estilos` es un
catalogo independiente y no un atributo fijo del artista.
- No se especifico el metodo de pago disponible; se asumen
`'efectivo'`, `'tarjeta'` y `'transferencia'` como los mas comunes.
- Se asume que una sesion cancelada no genera pago (no aplica el
`UNIQUE (id_sesion)` en ese caso porque simplemente no se inserta fila
en `pagos`).

## Preguntas que responde la base de datos

1. Cuales son todas las sesiones con su cliente, artista y estilo.
2. Que sesiones estan agendadas, completadas o canceladas.
3. Que artista tiene mas actividad (ranking por sesiones completadas).
4. Cuales son las sesiones ordenadas por fecha, de la mas reciente a la
mas antigua.
5. Cuanto se factura por estilo de tatuaje y cuales estilos superan un
monto minimo (reporte para decision de negocio).
Loading
Loading