From b4d2bde42cdb8d94646f0fb4014b995d94130dd5 Mon Sep 17 00:00:00 2001 From: MariaJoseMontepequeZet Date: Fri, 21 Aug 2026 16:28:48 -0600 Subject: [PATCH] feat(sql): resolver ejercicio 63 y solicitud sql 063 --- .../maria-montepeque/ejercicio-63/README.md | 70 +++++++++++++++++ .../ejercicio-63/ddl/schema.sql | 32 ++++++++ .../ejercicio-63/dml/inserts.sql | 35 +++++++++ .../ejercicio-63/dql/consultas.sql | 37 +++++++++ .../ejercicio-63/evidencias/resultados.md | 58 ++++++++++++++ .../solicitudes-sql/ejercicio-063/README.md | 78 +++++++++++++++++++ .../ejercicio-063/analisis/requerimiento.md | 64 +++++++++++++++ .../ejercicio-063/ddl/schema.sql | 50 ++++++++++++ .../ejercicio-063/diagramas/diagrama-er.svg | 50 ++++++++++++ .../ejercicio-063/dml/inserts.sql | 50 ++++++++++++ .../ejercicio-063/dml/operaciones.sql | 26 +++++++ .../ejercicio-063/dql/consultas.sql | 51 ++++++++++++ .../ejercicio-063/evidencias/resultados.md | 77 ++++++++++++++++++ 13 files changed, 678 insertions(+) create mode 100644 resoluciones/maria-montepeque/ejercicio-63/README.md create mode 100644 resoluciones/maria-montepeque/ejercicio-63/ddl/schema.sql create mode 100644 resoluciones/maria-montepeque/ejercicio-63/dml/inserts.sql create mode 100644 resoluciones/maria-montepeque/ejercicio-63/dql/consultas.sql create mode 100644 resoluciones/maria-montepeque/ejercicio-63/evidencias/resultados.md create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/README.md create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/analisis/requerimiento.md create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/ddl/schema.sql create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/diagramas/diagrama-er.svg create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/dml/inserts.sql create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/dml/operaciones.sql create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/dql/consultas.sql create mode 100644 resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/evidencias/resultados.md diff --git a/resoluciones/maria-montepeque/ejercicio-63/README.md b/resoluciones/maria-montepeque/ejercicio-63/README.md new file mode 100644 index 00000000..f48e3a0f --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-63/README.md @@ -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 +``` diff --git a/resoluciones/maria-montepeque/ejercicio-63/ddl/schema.sql b/resoluciones/maria-montepeque/ejercicio-63/ddl/schema.sql new file mode 100644 index 00000000..3f196c65 --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-63/ddl/schema.sql @@ -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) +); diff --git a/resoluciones/maria-montepeque/ejercicio-63/dml/inserts.sql b/resoluciones/maria-montepeque/ejercicio-63/dml/inserts.sql new file mode 100644 index 00000000..e820ee21 --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-63/dml/inserts.sql @@ -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); diff --git a/resoluciones/maria-montepeque/ejercicio-63/dql/consultas.sql b/resoluciones/maria-montepeque/ejercicio-63/dql/consultas.sql new file mode 100644 index 00000000..3a09fcaf --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-63/dql/consultas.sql @@ -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. diff --git a/resoluciones/maria-montepeque/ejercicio-63/evidencias/resultados.md b/resoluciones/maria-montepeque/ejercicio-63/evidencias/resultados.md new file mode 100644 index 00000000..f899f4d7 --- /dev/null +++ b/resoluciones/maria-montepeque/ejercicio-63/evidencias/resultados.md @@ -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. diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/README.md b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/README.md new file mode 100644 index 00000000..e5c07b1b --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/README.md @@ -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 +``` diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/analisis/requerimiento.md b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/analisis/requerimiento.md new file mode 100644 index 00000000..b67c05e7 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/analisis/requerimiento.md @@ -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). diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/ddl/schema.sql b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/ddl/schema.sql new file mode 100644 index 00000000..adb57e98 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/ddl/schema.sql @@ -0,0 +1,50 @@ +PRAGMA foreign_keys = ON; + +-- Ejercicio 063: Clinica de Tatuajes +-- Modelo: clientes, artistas, estilos, sesiones, pagos + +CREATE TABLE clientes ( + id_cliente INTEGER PRIMARY KEY AUTOINCREMENT, + nombre TEXT NOT NULL, + telefono TEXT NOT NULL UNIQUE +); + +CREATE TABLE artistas ( + id_artista INTEGER PRIMARY KEY AUTOINCREMENT, + nombre TEXT NOT NULL, + especialidad TEXT NOT NULL +); + +CREATE TABLE estilos ( + id_estilo INTEGER PRIMARY KEY AUTOINCREMENT, + nombre TEXT NOT NULL UNIQUE +); + +CREATE TABLE sesiones ( + id_sesion INTEGER PRIMARY KEY AUTOINCREMENT, + -- NOT NULL en las 3 relaciones: para evitar registros incompletos + -- que despues no permiten hacer reportes confiables. + id_cliente INTEGER NOT NULL, + id_artista INTEGER NOT NULL, + id_estilo INTEGER NOT NULL, + fecha_sesion TEXT NOT NULL DEFAULT (date('now')), + duracion_horas REAL NOT NULL CHECK (duracion_horas > 0), + estado TEXT NOT NULL DEFAULT 'agendada' + CHECK (estado IN ('agendada', 'completada', 'cancelada')), + + FOREIGN KEY (id_cliente) REFERENCES clientes (id_cliente), + FOREIGN KEY (id_artista) REFERENCES artistas (id_artista), + FOREIGN KEY (id_estilo) REFERENCES estilos (id_estilo) +); + +CREATE TABLE pagos ( + id_pago INTEGER PRIMARY KEY AUTOINCREMENT, + -- UNIQUE: cada sesion tiene como maximo un pago (relacion 1:1). + id_sesion INTEGER NOT NULL UNIQUE, + monto REAL NOT NULL CHECK (monto > 0), + metodo_pago TEXT NOT NULL CHECK (metodo_pago IN ('efectivo', 'tarjeta', 'transferencia')), + estado_pago TEXT NOT NULL DEFAULT 'pendiente' + CHECK (estado_pago IN ('pendiente', 'pagado', 'reembolsado')), + + FOREIGN KEY (id_sesion) REFERENCES sesiones (id_sesion) +); diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/diagramas/diagrama-er.svg b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/diagramas/diagrama-er.svg new file mode 100644 index 00000000..ec70ddf6 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/diagramas/diagrama-er.svg @@ -0,0 +1,50 @@ + + + + + clientes + id_cliente (PK) + telefono (UNIQUE) + + + artistas + id_artista (PK) + nombre, especialidad + + + estilos + id_estilo (PK) + nombre (UNIQUE) + + + sesiones + id_sesion (PK) + id_cliente (FK) + id_artista (FK) + id_estilo (FK) + duracion_horas, fecha_sesion + estado (CHECK) + + + pagos + id_pago (PK) + id_sesion (FK, UNIQUE) - monto, metodo_pago, estado_pago + + + 1 : N + + + 1 : N + + + 1 : N + + + 1 : 1 + diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/dml/inserts.sql b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/dml/inserts.sql new file mode 100644 index 00000000..5d5a5c01 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/dml/inserts.sql @@ -0,0 +1,50 @@ +PRAGMA foreign_keys = ON; + +-- Ejercicio 063: Clinica de Tatuajes +-- Datos base: 5 clientes, 3 artistas, 4 estilos, 10 sesiones, 6 pagos. + +INSERT INTO clientes (nombre, telefono) VALUES + ('Manuel Estrada', '5555-3001'), + ('Alejandra Chinchilla', '5555-3002'), + ('Byron Xicay', '5555-3003'), + ('Cristina Barrios', '5555-3004'), + ('Douglas Pineda', '5555-3005'); + +INSERT INTO artistas (nombre, especialidad) VALUES + ('Sergio Lopez', 'Realismo'), + ('Fernanda Castillo', 'Blackwork'), + ('Kevin Morales', 'Tradicional Japones'); + +INSERT INTO estilos (nombre) VALUES + ('Realismo'), + ('Blackwork'), + ('Tradicional Japones'), + ('Acuarela'); + +INSERT INTO sesiones (id_cliente, id_artista, id_estilo, fecha_sesion, duracion_horas, estado) VALUES + (1, 1, 1, '2026-07-01', 3.5, 'completada'), + (2, 2, 2, '2026-07-03', 2.0, 'completada'), + (3, 3, 3, '2026-07-05', 4.0, 'completada'), + (4, 1, 1, '2026-07-10', 1.5, 'completada'), + (5, 2, 2, '2026-07-12', 3.0, 'agendada'), + (1, 3, 3, '2026-07-15', 2.5, 'agendada'), + (2, 1, 1, '2026-07-18', 2.0, 'cancelada'), + (3, 2, 4, '2026-07-20', 3.5, 'completada'), + (4, 3, 2, '2026-07-22', 1.0, 'completada'), + (5, 1, 3, '2026-07-25', 4.5, 'agendada'); + +-- pagos: solo de sesiones ya completadas; la sesion 8 se registra con +-- pago pendiente (se confirma en operaciones.sql). +INSERT INTO pagos (id_sesion, monto, metodo_pago, estado_pago) VALUES + (1, 350.00, 'tarjeta', 'pagado'), + (2, 220.00, 'efectivo', 'pagado'), + (3, 480.00, 'transferencia', 'pagado'), + (4, 150.00, 'tarjeta', 'pagado'), + (9, 100.00, 'tarjeta', 'pagado'); + +INSERT INTO pagos (id_sesion, monto, metodo_pago) VALUES + (8, 380.00, 'efectivo'); + +-- Caso que debe fallar (queda comentado): registrar un segundo pago para +-- la misma sesion viola UNIQUE (id_sesion) en pagos. +-- INSERT INTO pagos (id_sesion, monto, metodo_pago) VALUES (1, 350.00, 'efectivo'); diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/dml/operaciones.sql b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/dml/operaciones.sql new file mode 100644 index 00000000..b0fc9ce4 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/dml/operaciones.sql @@ -0,0 +1,26 @@ +PRAGMA foreign_keys = ON; + +-- Ejercicio 063: Clinica de Tatuajes +-- Operaciones de mantenimiento sobre los datos base. + +-- 1 UPDATE de estado: la sesion 5 (agendada) se realiza y pasa a +-- 'completada'. +UPDATE sesiones +SET estado = 'completada' +WHERE id_sesion = 5; + +-- 1 UPDATE de estado: se confirma el pago pendiente de la sesion 8, una +-- vez que el cliente cancela en efectivo. +UPDATE pagos +SET estado_pago = 'pagado' +WHERE id_sesion = 8; + +-- 1 DELETE controlado: se elimina la sesion 7, que quedo 'cancelada' y +-- nunca genero pago (no rompe integridad referencial porque no existe +-- fila en pagos para id_sesion = 7). +DELETE FROM sesiones +WHERE id_sesion = 7 AND estado = 'cancelada'; + +-- Caso que debe fallar (queda comentado): eliminar un artista que tiene +-- sesiones asociadas viola la FOREIGN KEY de sesiones.id_artista. +-- DELETE FROM artistas WHERE id_artista = 1; diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/dql/consultas.sql b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/dql/consultas.sql new file mode 100644 index 00000000..986b5643 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/dql/consultas.sql @@ -0,0 +1,51 @@ +.headers on +.mode column + +-- Ejercicio 063: Clinica de Tatuajes +-- Consultas que responden preguntas reales del cliente. + +-- 1. Que registros principales existen: todas las sesiones con cliente, +-- artista y estilo. +SELECT s.id_sesion, + c.nombre AS cliente, + a.nombre AS artista, + e.nombre AS estilo, + s.duracion_horas, + s.estado +FROM sesiones s +JOIN clientes c ON c.id_cliente = s.id_cliente +JOIN artistas a ON a.id_artista = s.id_artista +JOIN estilos e ON e.id_estilo = s.id_estilo; + +-- 2. Que registros estan agendados, completados o cancelados. +SELECT id_sesion, estado +FROM sesiones +ORDER BY estado; + +-- 3. Que artista tiene mas actividad (ranking por sesiones completadas). +SELECT a.nombre AS artista, + COUNT(*) AS sesiones_completadas +FROM sesiones s +JOIN artistas a ON a.id_artista = s.id_artista +WHERE s.estado = 'completada' +GROUP BY a.id_artista +ORDER BY sesiones_completadas DESC; + +-- 4. Sesiones ordenadas por fecha, de la mas reciente a la mas antigua. +SELECT id_sesion, fecha_sesion, estado +FROM sesiones +ORDER BY fecha_sesion DESC; + +-- 5. Reporte para decision de negocio: facturacion por estilo, solo con +-- pagos ya 'pagado', filtrando los estilos que superan Q300 (GROUP BY + +-- HAVING). +SELECT e.nombre AS estilo, + COUNT(*) AS sesiones_pagadas, + SUM(pg.monto) AS total_facturado +FROM pagos pg +JOIN sesiones s ON s.id_sesion = pg.id_sesion +JOIN estilos e ON e.id_estilo = s.id_estilo +WHERE pg.estado_pago = 'pagado' +GROUP BY e.id_estilo +HAVING SUM(pg.monto) > 300 +ORDER BY total_facturado DESC; diff --git a/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/evidencias/resultados.md b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/evidencias/resultados.md new file mode 100644 index 00000000..60dbe7f7 --- /dev/null +++ b/resoluciones/maria-montepeque/solicitudes-sql/ejercicio-063/evidencias/resultados.md @@ -0,0 +1,77 @@ +# Evidencias - Ejercicio 063 + +## 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-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 +``` + +## Resultados importantes + +Conteo de datos base (despues de `inserts.sql`): + +```text +clientes -> 5 +artistas -> 3 +estilos -> 4 +sesiones -> 10 +pagos -> 6 +``` + +Caso que debe fallar - segundo pago para la misma sesion (`UNIQUE`): + +```text +Fallo como se esperaba: UNIQUE constraint failed: pagos.id_sesion +``` + +Despues de `operaciones.sql`: + +```text +sesiones -> 9 (se elimino la sesion 7, cancelada sin pago) +sesion 5 estado: ('completada',) -- ya no 'agendada' +pago sesion 8: ('pagado',) -- confirmado, ya no pendiente +sesion 7: None -- eliminada correctamente +``` + +Caso que debe fallar - eliminar artista con sesiones asociadas (`FOREIGN KEY`): + +```text +Fallo como se esperaba: FOREIGN KEY constraint failed +``` + +Consulta 3 (ranking de artistas por sesiones completadas): + +```text +artista sesiones_completadas +Fernanda Castillo 3 +Kevin Morales 2 +Sergio Lopez 2 +``` + +Consulta 5 (facturacion por estilo, solo pagos 'pagado', HAVING > Q300): + +```text +estilo sesiones_pagadas total_facturado +Realismo 2 500.0 +Tradicional Japones 1 480.0 +Acuarela 1 380.0 +Blackwork 2 320.0 +``` + +## Explicacion final + +El modelo separa catalogos (`clientes`, `artistas`, `estilos`) de la +tabla transaccional (`sesiones`) y del movimiento de dinero (`pagos`). +Los campos `id_cliente`, `id_artista` e `id_estilo` de `sesiones` son +`NOT NULL` a proposito: eso evita el problema que el cliente describio +(registros incompletos que despues no permiten reportes confiables). +Con `JOIN`, `GROUP BY` y `HAVING` se responde exactamente lo que el +estudio necesita: que artista tiene mas actividad y que estilo genera +mas ingresos.