Este documento reúne, secuencia por secuencia, el trabajo resuelto durante el curso de Programación (M3S1): modelado entidad-relación, lenguaje SQL para creación y consulta de bases de datos, normalización, diseño multidimensional (OLAP) y el proceso ETL. Concluyendo con el proyecto final, la base de datos y el sistema CRUD.
「Modelo Entidad-Relación」
9 — 13 de febrero de 2026Ejercicios integradores. Para cada caso se identifican entidades, atributos, relaciones y cardinalidad.
Caso 1 — Sistema de Renta de Vehículos
ENTIDADES · ATRIBUTOS · CARDINALIDADEntidades y atributos
| Entidad | Atributos |
|---|---|
| CLIENTE | id_cliente (PK), nombre, apellido, telefono, correo, direccion, fecha_nacimiento, licencia, tipo_licencia |
| VEHICULO | id_vehiculo (PK), placa, marca, modelo, anio, color, tipo, kilometraje, precio_dia, disponible |
| CONTRATO | id_contrato (PK), fecha_inicio, fecha_fin, total, deposito, estado, id_cliente (FK), id_vehiculo (FK), lugar_entrega, observaciones |
Relaciones y cardinalidad
- CLIENTE — realiza → CONTRATO (1:N) — un cliente puede tener muchos contratos.
- VEHICULO — aparece en → CONTRATO (1:N) — un vehículo puede tener muchos contratos en distintas fechas.
Descripción del diagrama E-R
CLIENTE (óvalo con atributos) —[realiza]— CONTRATO —[pertenece a]— VEHICULO. Cardinalidad: CLIENTE 1:N CONTRATO ; VEHICULO 1:N CONTRATO.
Caso 2 — Sistema de Eventos y Boletos
ENTIDADES · ATRIBUTOS · CARDINALIDADEntidades y atributos
| Entidad | Atributos |
|---|---|
| CLIENTE | id_cliente (PK), nombre, apellido, correo, telefono, direccion, fecha_registro, tipo_usuario, metodo_pago |
| EVENTO | id_evento (PK), nombre, descripcion, fecha, hora, lugar, capacidad, precio_general, organizador, categoria |
| BOLETO | id_boleto (PK), codigo, tipo_asiento, precio, fecha_compra, estado, id_cliente (FK), id_evento (FK), numero_asiento, forma_pago |
Relaciones y cardinalidad
- CLIENTE — compra → BOLETO (1:N) — un cliente puede comprar muchos boletos.
- EVENTO — tiene → BOLETO (1:N) — un evento puede tener muchos boletos.
- CLIENTE ↔ EVENTO vía BOLETO (N:M).
Caso 3 — Sistema de Gimnasio
ENTIDADES · ATRIBUTOS · CARDINALIDADEntidades y atributos
| Entidad | Atributos |
|---|---|
| SOCIO | id_socio (PK), nombre, apellido, telefono, correo, fecha_inscripcion, tipo_membresia, fecha_nacimiento, peso, estatura |
| ENTRENADOR | id_entrenador (PK), nombre, apellido, especialidad, certificacion, telefono, correo, anos_experiencia, horario, salario |
| RUTINA | id_rutina (PK), nombre, descripcion, nivel_dificultad, duracion_minutos, objetivo, fecha_creacion, id_entrenador (FK), tipo_ejercicio, frecuencia_semanal |
Relaciones y cardinalidad
- ENTRENADOR — crea → RUTINA (1:N) — un entrenador puede crear muchas rutinas.
- SOCIO ↔ RUTINA (N:M) — un socio puede tener varias rutinas y una rutina puede asignarse a muchos socios.
- Tabla intermedia: ASIGNACION(id_asignacion PK, id_socio FK, id_rutina FK, fecha_asignacion, estado).
「Diseño Lógico con SQL」
16 — 27 de febrero de 2026Código SQL completo para los cinco ejercicios planteados: creación de bases de datos, tablas, llaves foráneas y datos de ejemplo.
Ejercicio 1 — Sistema de Biblioteca Intercultural
RELACIÓN N:M ENTRE AUTOR Y LIBRO
CREATE DATABASE BibliotecaIntercultural;
USE BibliotecaIntercultural;
CREATE TABLE Autor (
id_autor INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
nacionalidad VARCHAR(50)
);
CREATE TABLE Libro (
ISBN VARCHAR(20) PRIMARY KEY,
titulo VARCHAR(150) NOT NULL,
anio INT
);
-- Relacion N:M entre Autor y Libro
CREATE TABLE Autor_Libro (
id_autor INT,
ISBN VARCHAR(20),
PRIMARY KEY (id_autor, ISBN),
FOREIGN KEY (id_autor) REFERENCES Autor(id_autor),
FOREIGN KEY (ISBN) REFERENCES Libro(ISBN)
);
CREATE TABLE Usuario (
id_usuario INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
correo VARCHAR(100)
);
CREATE TABLE Prestamo (
id_prestamo INT PRIMARY KEY AUTO_INCREMENT,
fecha_inicio DATE,
fecha_devolucion DATE,
id_usuario INT,
ISBN VARCHAR(20),
FOREIGN KEY (id_usuario) REFERENCES Usuario(id_usuario),
FOREIGN KEY (ISBN) REFERENCES Libro(ISBN)
);
-- Datos de ejemplo
INSERT INTO Autor (nombre, nacionalidad) VALUES
('Gabriel Garcia Marquez', 'Colombiana'),
('Octavio Paz', 'Mexicana'),
('Isabel Allende', 'Chilena');
INSERT INTO Libro (ISBN, titulo, anio) VALUES
('978-1', 'Cien Anos de Soledad', 1967),
('978-2', 'El Laberinto de la Soledad', 1950),
('978-3', 'La Casa de los Espiritus', 1982);
INSERT INTO Autor_Libro VALUES (1,'978-1'), (2,'978-2'), (3,'978-3');
INSERT INTO Usuario (nombre, correo) VALUES
('Maria Lopez', 'maria@mail.com'),
('Pedro Ruiz', 'pedro@mail.com');
INSERT INTO Prestamo (fecha_inicio, fecha_devolucion, id_usuario, ISBN) VALUES
('2025-09-01', '2025-09-15', 1, '978-1'),
('2025-09-05', NULL, 2, '978-2');
Ejercicio 2 — Centro de Desarrollo Infantil
RELACIÓN N:M NIÑO – ACTIVIDAD
CREATE DATABASE CentroInfantil;
USE CentroInfantil;
CREATE TABLE Educadora (
clave INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
especialidad VARCHAR(80)
);
CREATE TABLE Actividad (
codigo INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
horario VARCHAR(50),
clave_educadora INT,
FOREIGN KEY (clave_educadora) REFERENCES Educadora(clave)
);
CREATE TABLE Nino (
matricula INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
edad INT
);
-- Relacion N:M Nino - Actividad
CREATE TABLE Nino_Actividad (
matricula INT,
codigo INT,
PRIMARY KEY (matricula, codigo),
FOREIGN KEY (matricula) REFERENCES Nino(matricula),
FOREIGN KEY (codigo) REFERENCES Actividad(codigo)
);
INSERT INTO Educadora (nombre, especialidad) VALUES
('Lupita Gomez', 'Musica'), ('Rosa Medina', 'Arte');
INSERT INTO Actividad (nombre, horario, clave_educadora) VALUES
('Musica y ritmo', 'Lunes 9:00', 1),
('Pintura creativa', 'Martes 10:00', 2),
('Canto coral', 'Miercoles 9:00', 1);
INSERT INTO Nino (nombre, edad) VALUES
('Sofia R.', 4), ('Diego M.', 5), ('Camila P.', 4);
INSERT INTO Nino_Actividad VALUES (1,1),(1,2),(2,1),(2,3),(3,2);
Ejercicio 3 — Sistema de Huerto Escolar
RELACIÓN N:M ESTUDIANTE – PARCELA--
CREATE DATABASE HuertoEscolar;
USE HuertoEscolar;
CREATE TABLE Parcela (
numero_parcela INT PRIMARY KEY AUTO_INCREMENT,
tamanio DECIMAL(8,2) -- metros cuadrados
);
CREATE TABLE Cultivo (
codigo INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(80) NOT NULL,
tipo VARCHAR(50),
numero_parcela INT,
FOREIGN KEY (numero_parcela) REFERENCES Parcela(numero_parcela)
);
CREATE TABLE Estudiante (
id_estudiante INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
grupo VARCHAR(20)
);
-- N:M Estudiante - Parcela
CREATE TABLE Estudiante_Parcela (
id_estudiante INT,
numero_parcela INT,
PRIMARY KEY (id_estudiante, numero_parcela),
FOREIGN KEY (id_estudiante) REFERENCES Estudiante(id_estudiante),
FOREIGN KEY (numero_parcela) REFERENCES Parcela(numero_parcela)
);
INSERT INTO Parcela (tamanio) VALUES (20.5),(15.0),(30.0);
INSERT INTO Cultivo (nombre, tipo, numero_parcela) VALUES
('Jitomate','Hortaliza',1),('Chile','Hortaliza',1),
('Cilantro','Hierba',2),('Maiz','Cereal',3);
INSERT INTO Estudiante (nombre, grupo) VALUES
('Ana P.','3A'),('Luis Q.','3B'),('Fernanda R.','3A');
INSERT INTO Estudiante_Parcela VALUES (1,1),(1,3),(2,2),(3,1),(3,2);
Ejercicio 4 — Plataforma de Cursos de Programación
RELACIÓN N:M ESTUDIANTE – CURSO
CREATE DATABASE PlataformaCursos;
USE PlataformaCursos;
CREATE TABLE Instructor (
id_instructor INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
especialidad VARCHAR(80)
);
CREATE TABLE Curso (
codigo INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
duracion INT, -- horas
id_instructor INT,
FOREIGN KEY (id_instructor) REFERENCES Instructor(id_instructor)
);
CREATE TABLE Estudiante (
id_estudiante INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
correo VARCHAR(100)
);
-- N:M Estudiante - Curso
CREATE TABLE Inscripcion (
id_estudiante INT,
codigo INT,
fecha_inscripcion DATE,
PRIMARY KEY (id_estudiante, codigo),
FOREIGN KEY (id_estudiante) REFERENCES Estudiante(id_estudiante),
FOREIGN KEY (codigo) REFERENCES Curso(codigo)
);
INSERT INTO Instructor (nombre, especialidad) VALUES
('Carlos Vega', 'Python'), ('Ana Rios', 'Web');
INSERT INTO Curso (nombre, duracion, id_instructor) VALUES
('Python Basico', 40, 1),('HTML y CSS', 30, 2),('Python Avanzado', 60, 1);
INSERT INTO Estudiante (nombre, correo) VALUES
('Pedro M.', 'pedro@mail.com'),('Laura S.', 'laura@mail.com');
INSERT INTO Inscripcion VALUES
(1,1,'2025-09-01'),(1,3,'2025-09-15'),(2,2,'2025-09-01'),(2,1,'2025-09-10');
Ejercicio 5 — Clínica Comunitaria
RELACIÓN 1:N PACIENTE / MEDICO – CONSULTA
CREATE DATABASE ClinicaComunitaria;
USE ClinicaComunitaria;
CREATE TABLE Paciente (
num_expediente INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
edad INT
);
CREATE TABLE Medico (
cedula INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
especialidad VARCHAR(80)
);
CREATE TABLE Consulta (
id_consulta INT PRIMARY KEY AUTO_INCREMENT,
fecha DATE NOT NULL,
diagnostico VARCHAR(200),
num_expediente INT,
cedula INT,
FOREIGN KEY (num_expediente) REFERENCES Paciente(num_expediente),
FOREIGN KEY (cedula) REFERENCES Medico(cedula)
);
INSERT INTO Paciente (nombre, edad) VALUES
('Juan Torres', 45),('Maria Garcia', 30),('Pedro Soto', 60);
INSERT INTO Medico (nombre, especialidad) VALUES
('Dr. Lopez', 'General'),('Dra. Ruiz', 'Cardiologia');
INSERT INTO Consulta (fecha, diagnostico, num_expediente, cedula) VALUES
('2025-10-01','Hipertension leve',1,2),
('2025-10-02','Gripe comun',2,1),
('2025-10-03','Control de rutina',3,2);
「Normalización — Galería de Arte」
2 — 6 de marzo de 2026Identificación de entidades y atributos, cardinalidades, código SQL normalizado y demostración del cumplimiento de las cinco formas normales.
Entidades y atributos identificados
| Entidad | Atributos | PK |
|---|---|---|
| PERSONA | id_persona, nombre, correo, telefono | id_persona |
| ARTISTA (subconjunto de Persona) | id_persona (FK), estilo_predominante | id_persona |
| OBRA | num_registro, titulo, estilo, precio_salida, id_artista (FK) | num_registro |
| PROPIETARIO_OBRA | id_persona (FK), num_registro (FK) | id_persona + num_registro |
| EXPOSICION | id_exposicion, titulo, descripcion, fecha_inauguracion, fecha_clausura | id_exposicion |
| OBRA_EXPOSICION | num_registro (FK), id_exposicion (FK) | num_registro + id_exposicion |
| OFERTA | id_oferta, monto, fecha, id_persona (FK), num_registro (FK) | id_oferta |
Relaciones y cardinalidades
- PERSONA — es artista de → OBRA (1:N) — una persona-artista puede crear muchas obras.
- PERSONA — posee → OBRA (N:M) — una persona puede poseer varias obras; una obra tiene un propietario.
- EXPOSICION ↔ OBRA (N:M) — una exposición tiene muchas obras; una obra puede estar en varias exposiciones.
- PERSONA — hace → OFERTA (1:N) — una persona puede hacer muchas ofertas.
- OBRA — recibe → OFERTA (1:N) — una obra puede recibir muchas ofertas.
Código SQL — Galería de Arte (cumple 5FN)
CREATE DATABASE GaleriaArte;
USE GaleriaArte;
-- 1FN, 2FN, 3FN: Sin grupos repetidos, sin dependencias parciales ni transitivas
CREATE TABLE Persona (
id_persona INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
correo VARCHAR(100),
telefono VARCHAR(20)
);
-- Especializacion: una persona puede ser artista
CREATE TABLE Artista (
id_persona INT PRIMARY KEY,
estilo_predominante VARCHAR(80),
FOREIGN KEY (id_persona) REFERENCES Persona(id_persona)
);
CREATE TABLE Exposicion (
id_exposicion INT PRIMARY KEY AUTO_INCREMENT,
titulo VARCHAR(150) NOT NULL,
descripcion TEXT,
fecha_inauguracion DATE,
fecha_clausura DATE
);
CREATE TABLE Obra (
num_registro INT PRIMARY KEY AUTO_INCREMENT,
titulo VARCHAR(150) NOT NULL,
estilo VARCHAR(80),
precio_salida DECIMAL(12,2),
id_artista INT,
FOREIGN KEY (id_artista) REFERENCES Artista(id_persona)
);
-- Una obra tiene un propietario actual (puede ser distinto al artista)
CREATE TABLE Propietario_Obra (
id_persona INT,
num_registro INT,
PRIMARY KEY (id_persona, num_registro),
FOREIGN KEY (id_persona) REFERENCES Persona(id_persona),
FOREIGN KEY (num_registro) REFERENCES Obra(num_registro)
);
-- N:M Obra - Exposicion
CREATE TABLE Obra_Exposicion (
num_registro INT,
id_exposicion INT,
PRIMARY KEY (num_registro, id_exposicion),
FOREIGN KEY (num_registro) REFERENCES Obra(num_registro),
FOREIGN KEY (id_exposicion) REFERENCES Exposicion(id_exposicion)
);
CREATE TABLE Oferta (
id_oferta INT PRIMARY KEY AUTO_INCREMENT,
monto DECIMAL(12,2) NOT NULL,
fecha DATE NOT NULL,
id_persona INT,
num_registro INT,
ganadora BOOLEAN DEFAULT FALSE,
FOREIGN KEY (id_persona) REFERENCES Persona(id_persona),
FOREIGN KEY (num_registro) REFERENCES Obra(num_registro)
);
-- Datos de ejemplo
INSERT INTO Persona (nombre, correo) VALUES
('Frida Mendez','frida@art.mx'),
('Diego Vargas','diego@art.mx'),
('Carlos Rios','carlos@col.mx'),
('Laura Vega','laura@col.mx');
INSERT INTO Artista VALUES (1,'Surrealismo'),(2,'Muralismo');
INSERT INTO Exposicion (titulo, descripcion, fecha_inauguracion, fecha_clausura) VALUES
('Arte Moderno MX','Exposicion de arte contemporaneo mexicano','2025-11-01','2025-11-30');
INSERT INTO Obra (titulo, estilo, precio_salida, id_artista) VALUES
('Sueno Roto','Surrealismo',50000.00,1),
('Raices','Muralismo',80000.00,2);
INSERT INTO Propietario_Obra VALUES (1,1),(2,2);
INSERT INTO Obra_Exposicion VALUES (1,1),(2,1);
INSERT INTO Oferta (monto, fecha, id_persona, num_registro) VALUES
(52000,'2025-11-25',3,1),
(85000,'2025-11-26',4,2);
Demostración de formas normales
| Forma normal | Cumplimiento |
|---|---|
| 1FN — Valores atómicos | Todos los campos son atómicos, sin grupos repetidos ni listas. |
| 2FN — Sin dependencias parciales | Las claves compuestas (Propietario_Obra, Obra_Exposicion) no tienen atributos con dependencia parcial. |
| 3FN — Sin dependencias transitivas | No hay atributos que dependan de otros atributos no clave. |
| 4FN — Sin dependencias multivaluadas | Propietario y Exposicion son tablas independientes, sin multivaluados. |
| 5FN — Sin dependencias de join | Cada relación N:M se maneja con tabla intermedia; no hay información perdida al descomponer. |
porsilasmoscas
meow.
"Una base de datos bien normalizada no olvida nada — solo guarda cada cosa en el lugar que le corresponde."
「Caso Clínica — Ejercicios SQL」
9 — 13 de marzo de 2026Planteamiento 1 — Pacientes mayores de 20 años
-- Mostrar nombre, direccion y edad de pacientes con edad > 20 SELECT nombre, direccion, edad FROM Paciente WHERE edad > 20;
Planteamiento 2 — Todas las citas registradas
-- Mostrar fecha, hora y motivo de todas las citas SELECT fecha, hora, motivo FROM Cita;
「Caso Hotel — Consultas SQL」
16 — 20 de marzo de 2026Planteamiento 1 — Reservas de más de 2 días
-- Mostrar clientes y fechas de reservas que duran mas de 2 dias
SELECT
Cliente.nombre AS Cliente,
Reserva.fecha_entrada,
Reserva.fecha_salida,
DATEDIFF(Reserva.fecha_salida, Reserva.fecha_entrada) AS dias_estancia
FROM Reserva
INNER JOIN Cliente ON Reserva.id_cliente = Cliente.id_cliente
WHERE DATEDIFF(Reserva.fecha_salida, Reserva.fecha_entrada) > 2;
Planteamiento 2 — Habitaciones tipo Doble
-- Mostrar habitaciones de tipo Doble SELECT numero, tipo, precio FROM Habitacion WHERE tipo = 'Doble';
Actividad 3 — Sistema de Viajes (diagrama E-R: Viajero–Viaje–Destino–Origen)
VIAJERO 1:N VIAJE · VIAJE 1:1 DESTINO · VIAJE 1:1 ORIGEN
CREATE DATABASE SistemaViajes;
USE SistemaViajes;
CREATE TABLE Origen (
codigo INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
otros VARCHAR(100)
);
CREATE TABLE Destino (
codigo INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
otros VARCHAR(100)
);
CREATE TABLE Viajero (
DNI INT PRIMARY KEY,
nombre VARCHAR(100) NOT NULL,
direccion VARCHAR(150),
telefono VARCHAR(20)
);
CREATE TABLE Viaje (
codigo INT PRIMARY KEY AUTO_INCREMENT,
num_plazas INT NOT NULL,
fecha_del_viaje DATE NOT NULL,
otros VARCHAR(100),
DNI_viajero INT,
codigo_destino INT,
codigo_origen INT,
FOREIGN KEY (DNI_viajero) REFERENCES Viajero(DNI),
FOREIGN KEY (codigo_destino) REFERENCES Destino(codigo),
FOREIGN KEY (codigo_origen) REFERENCES Origen(codigo)
);
-- Datos de ejemplo
INSERT INTO Origen (nombre, otros) VALUES
('Ciudad de Mexico','Capital'),
('Guadalajara','Jalisco'),
('Monterrey','Nuevo Leon');
INSERT INTO Destino (nombre, otros) VALUES
('Cancun','Quintana Roo'),
('Los Cabos','Baja California Sur'),
('Oaxaca','Oaxaca');
INSERT INTO Viajero (DNI, nombre, direccion, telefono) VALUES
(1001,'Luis Hernandez','Av. Reforma 100','7711234567'),
(1002,'Ana Martinez','Calle Juarez 45','7717654321'),
(1003,'Carlos Perez','Col. Centro 200','7719876543');
INSERT INTO Viaje (num_plazas, fecha_del_viaje, DNI_viajero, codigo_destino, codigo_origen) VALUES
(2,'2025-12-20',1001,1,1),
(1,'2025-12-25',1002,2,2),
(4,'2026-01-05',1003,3,3);
-- Consultas de ejemplo: ver viajes con viajero, origen y destino
SELECT
V.nombre AS Viajero,
Vi.fecha_del_viaje,
Vi.num_plazas,
O.nombre AS Origen,
D.nombre AS Destino
FROM Viaje Vi
INNER JOIN Viajero V ON Vi.DNI_viajero = V.DNI
INNER JOIN Origen O ON Vi.codigo_origen = O.codigo
INNER JOIN Destino D ON Vi.codigo_destino = D.codigo;
「Consumo de Energía Eléctrica」
23 — 27 de marzo de 2026Ejercicio 3: modelo multidimensional para el análisis del consumo eléctrico.
Modelo multidimensional
| Elemento | Detalle |
|---|---|
| Hecho | Consumo (kWh) |
| Dimensión Tiempo | mes, año |
| Dimensión Zona | tipo: urbana / rural |
| Dimensión Tipo de usuario | hogar, negocio, industria |
¿Qué permite analizar este modelo?
- Patrones de consumo: cuánto se consume por mes o año y en qué temporadas hay mayor uso.
- Diferencias por tipo de usuario: comparar consumo entre hogares, negocios e industrias.
- Distribución geográfica: qué zonas, urbanas o rurales, consumen más energía.
- Tendencias: incrementos o disminuciones en el consumo a lo largo del tiempo.
- Toma de decisiones: optimizar el suministro, implementar estrategias de ahorro y planificar infraestructura.
Código SQL — Consumo de Energía
CREATE DATABASE EnergiaDW;
USE EnergiaDW;
-- Dimension Tiempo
CREATE TABLE Tiempo (
id_tiempo INT PRIMARY KEY AUTO_INCREMENT,
mes VARCHAR(20),
anio INT
);
-- Dimension Zona
CREATE TABLE Zona (
id_zona INT PRIMARY KEY AUTO_INCREMENT,
tipo VARCHAR(20) CHECK (tipo IN ('urbana','rural'))
);
-- Dimension Tipo de Usuario
CREATE TABLE TipoUsuario (
id_tipo INT PRIMARY KEY AUTO_INCREMENT,
categoria VARCHAR(30) CHECK (categoria IN ('hogar','negocio','industria'))
);
-- Tabla de Hechos: Consumo
CREATE TABLE Consumo (
id_consumo INT PRIMARY KEY AUTO_INCREMENT,
id_tiempo INT,
id_zona INT,
id_tipo INT,
kwh DECIMAL(10,2),
FOREIGN KEY (id_tiempo) REFERENCES Tiempo(id_tiempo),
FOREIGN KEY (id_zona) REFERENCES Zona(id_zona),
FOREIGN KEY (id_tipo) REFERENCES TipoUsuario(id_tipo)
);
-- Insertar datos
INSERT INTO Tiempo (mes, anio) VALUES
('Enero',2025),('Febrero',2025),('Marzo',2025),
('Abril',2025),('Mayo',2025),('Junio',2025);
INSERT INTO Zona (tipo) VALUES ('urbana'),('rural');
INSERT INTO TipoUsuario (categoria) VALUES
('hogar'),('negocio'),('industria');
INSERT INTO Consumo (id_tiempo, id_zona, id_tipo, kwh) VALUES
(1,1,1,1200),(1,1,2,3500),(1,1,3,9000),
(1,2,1,800),(1,2,2,1500),(1,2,3,4000),
(2,1,1,1100),(2,1,2,3200),(2,1,3,8500),
(3,1,1,950),(3,2,1,780),(3,2,2,1400),
(4,1,3,9500),(5,1,1,1050),(6,1,2,3800);
-- CONSULTAS OLAP
-- Consumo total por tipo de usuario (decidir donde enfocar ahorro)
SELECT
TipoUsuario.categoria,
SUM(Consumo.kwh) AS total_kwh
FROM Consumo
INNER JOIN TipoUsuario ON Consumo.id_tipo = TipoUsuario.id_tipo
GROUP BY TipoUsuario.categoria
ORDER BY total_kwh DESC;
-- Consumo por mes (detectar temporadas pico)
SELECT
Tiempo.mes,
Tiempo.anio,
SUM(Consumo.kwh) AS total_kwh
FROM Consumo
INNER JOIN Tiempo ON Consumo.id_tiempo = Tiempo.id_tiempo
GROUP BY Tiempo.mes, Tiempo.anio
ORDER BY total_kwh DESC;
-- Consumo por zona
SELECT
Zona.tipo AS zona,
SUM(Consumo.kwh) AS total_kwh
FROM Consumo
INNER JOIN Zona ON Consumo.id_zona = Zona.id_zona
GROUP BY Zona.tipo;
Toma de decisiones
- ¿A qué sector enfocar campañas de ahorro? → Al sector industria, que consume más kWh.
- ¿En qué meses reforzar el suministro? → Abril y junio, meses con mayor consumo.
- ¿Qué zona requiere mayor inversión en infraestructura? → La zona urbana por mayor demanda total.
「Modelos Multidimensionales — Ejercicios 1, 2 y 3」
13 — 17 de abril de 2026Ejercicio 1 — Ventas de Supermercado
¿Qué permite analizar?
- Productos más vendidos por categoría y sucursal.
- Ventas por período de tiempo (día, mes, año).
- Qué sucursal tiene mayor rendimiento.
- Toma de decisiones: ajustar inventario y mejorar estrategias de venta por sucursal.
CREATE DATABASE SupermercadoDW;
USE SupermercadoDW;
CREATE TABLE Tiempo (
id_tiempo INT PRIMARY KEY AUTO_INCREMENT,
dia INT, mes VARCHAR(20), anio INT
);
CREATE TABLE Producto (
id_producto INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(80),
categoria VARCHAR(50)
);
CREATE TABLE Sucursal (
id_sucursal INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(80),
ciudad VARCHAR(50)
);
CREATE TABLE Ventas (
id_venta INT PRIMARY KEY AUTO_INCREMENT,
id_tiempo INT, id_producto INT, id_sucursal INT,
cantidad INT, total DECIMAL(10,2),
FOREIGN KEY (id_tiempo) REFERENCES Tiempo(id_tiempo),
FOREIGN KEY (id_producto) REFERENCES Producto(id_producto),
FOREIGN KEY (id_sucursal) REFERENCES Sucursal(id_sucursal)
);
INSERT INTO Tiempo (dia, mes, anio) VALUES
(1,'Enero',2025),(15,'Enero',2025),(5,'Febrero',2025),
(20,'Febrero',2025),(10,'Marzo',2025);
INSERT INTO Producto (nombre, categoria) VALUES
('Leche Lala 1L','Lacteos'),
('Pan Bimbo','Panaderia'),
('Coca-Cola 600ml','Bebidas'),
('Arroz 1kg','Granos'),
('Aceite 1L','Aceites');
INSERT INTO Sucursal (nombre, ciudad) VALUES
('Sucursal Norte','Pachuca'),
('Sucursal Centro','Pachuca'),
('Sucursal Sur','Tulancingo');
INSERT INTO Ventas (id_tiempo,id_producto,id_sucursal,cantidad,total) VALUES
(1,1,1,50,750),(1,2,1,30,450),(2,3,2,80,960),
(3,4,3,40,600),(4,1,2,60,900),(5,5,1,25,875),
(3,2,3,45,675),(4,3,1,90,1080);
-- CONSULTAS
-- Productos mas vendidos
SELECT
p.nombre, p.categoria,
SUM(v.cantidad) AS unidades_vendidas,
SUM(v.total) AS total_ventas
FROM Ventas v
INNER JOIN Producto p ON v.id_producto = p.id_producto
GROUP BY p.nombre, p.categoria
ORDER BY total_ventas DESC;
-- Ventas por sucursal
SELECT
s.nombre AS sucursal,
SUM(v.total) AS total_ventas
FROM Ventas v
INNER JOIN Sucursal s ON v.id_sucursal = s.id_sucursal
GROUP BY s.nombre
ORDER BY total_ventas DESC;
Ejercicio 2 — Asistencia Escolar
¿Qué permite analizar?
- Patrones de asistencia y ausentismo por alumno, grupo y fecha.
- Días o meses con mayor ausentismo.
- Comparar asistencia entre grupos.
- Toma de decisiones: implementar tutorías y seguimiento para mejorar la asistencia.
CREATE DATABASE AsistenciaEscolarDW;
USE AsistenciaEscolarDW;
CREATE TABLE Alumno (
id_alumno INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100)
);
CREATE TABLE Fecha (
id_fecha INT PRIMARY KEY AUTO_INCREMENT,
dia INT, mes VARCHAR(20), anio INT
);
CREATE TABLE Grupo (
id_grupo INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(20),
grado VARCHAR(20)
);
-- Tabla de Hechos
CREATE TABLE Asistencias (
id_asistencia INT PRIMARY KEY AUTO_INCREMENT,
id_alumno INT, id_fecha INT, id_grupo INT,
presente TINYINT(1), -- 1 = asistio, 0 = falto
FOREIGN KEY (id_alumno) REFERENCES Alumno(id_alumno),
FOREIGN KEY (id_fecha) REFERENCES Fecha(id_fecha),
FOREIGN KEY (id_grupo) REFERENCES Grupo(id_grupo)
);
INSERT INTO Alumno (nombre) VALUES
('Juan Perez'),('Maria Lopez'),('Carlos Ruiz'),
('Ana Torres'),('Pedro Soto');
INSERT INTO Fecha (dia, mes, anio) VALUES
(7,'Abril',2025),(8,'Abril',2025),(9,'Abril',2025),
(10,'Abril',2025),(14,'Abril',2025);
INSERT INTO Grupo (nombre, grado) VALUES
('4A','Cuarto'),('4B','Cuarto'),('4C','Cuarto');
INSERT INTO Asistencias (id_alumno,id_fecha,id_grupo,presente) VALUES
(1,1,1,1),(1,2,1,1),(1,3,1,0),(1,4,1,1),(1,5,1,0),
(2,1,1,1),(2,2,1,0),(2,3,1,1),(2,4,1,1),(2,5,1,1),
(3,1,2,0),(3,2,2,0),(3,3,2,1),(3,4,2,1),(3,5,2,0),
(4,1,2,1),(4,2,2,1),(4,3,2,1),(4,4,2,0),(4,5,2,1),
(5,1,3,1),(5,2,3,1),(5,3,3,1),(5,4,3,1),(5,5,3,1);
-- CONSULTAS
-- Porcentaje de asistencia por alumno
SELECT
a.nombre,
SUM(ast.presente) AS dias_asistidos,
COUNT(*) AS total_dias,
ROUND(SUM(ast.presente)/COUNT(*)*100, 1) AS porcentaje_asistencia
FROM Asistencias ast
INNER JOIN Alumno a ON ast.id_alumno = a.id_alumno
GROUP BY a.nombre
ORDER BY porcentaje_asistencia ASC;
-- Ausentismo por grupo (para estrategias de mejora)
SELECT
g.nombre AS grupo,
SUM(CASE WHEN ast.presente = 0 THEN 1 ELSE 0 END) AS total_faltas,
COUNT(*) AS registros_totales
FROM Asistencias ast
INNER JOIN Grupo g ON ast.id_grupo = g.id_grupo
GROUP BY g.nombre
ORDER BY total_faltas DESC;
Ejercicio 3 — Uso de Transporte Público
¿Qué permite analizar?
- Rutas y horarios más utilizados.
- Tipo de usuario que más usa el transporte (estudiante, trabajador, adulto mayor).
- Variación del uso por mes o día de la semana.
- Toma de decisiones: optimizar rutas frecuentes y aumentar unidades en horarios pico.
CREATE DATABASE TransporteDW;
USE TransporteDW;
CREATE TABLE Ruta (
id_ruta INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(80),
origen VARCHAR(80),
destino VARCHAR(80)
);
CREATE TABLE Tiempo (
id_tiempo INT PRIMARY KEY AUTO_INCREMENT,
dia INT, mes VARCHAR(20), hora INT
);
CREATE TABLE Usuario (
id_usuario INT PRIMARY KEY AUTO_INCREMENT,
tipo VARCHAR(30) -- estudiante, trabajador, adulto mayor
);
-- Tabla de Hechos
CREATE TABLE Viajes (
id_viaje INT PRIMARY KEY AUTO_INCREMENT,
id_ruta INT, id_tiempo INT, id_usuario INT,
num_viajes INT,
FOREIGN KEY (id_ruta) REFERENCES Ruta(id_ruta),
FOREIGN KEY (id_tiempo) REFERENCES Tiempo(id_tiempo),
FOREIGN KEY (id_usuario) REFERENCES Usuario(id_usuario)
);
INSERT INTO Ruta (nombre, origen, destino) VALUES
('Ruta 1','Centro','Universidad'),
('Ruta 2','Norte','Hospital'),
('Ruta 3','Sur','Centro Comercial'),
('Ruta 4','Este','Estacion Central');
INSERT INTO Tiempo (dia, mes, hora) VALUES
(7,'Abril',7),(7,'Abril',8),(7,'Abril',14),
(8,'Abril',7),(8,'Abril',13),(8,'Mayo',8);
INSERT INTO Usuario (tipo) VALUES
('estudiante'),('trabajador'),('adulto mayor'),('estudiante'),('trabajador');
INSERT INTO Viajes (id_ruta,id_tiempo,id_usuario,num_viajes) VALUES
(1,1,1,120),(1,2,2,200),(2,1,3,80),(2,2,2,150),
(3,3,1,90),(4,4,2,180),(1,5,4,110),(3,6,5,130),
(2,4,1,95),(4,3,5,160);
-- CONSULTAS
-- Rutas mas utilizadas (para aumentar unidades)
SELECT
r.nombre AS ruta,
SUM(v.num_viajes) AS total_viajes
FROM Viajes v
INNER JOIN Ruta r ON v.id_ruta = r.id_ruta
GROUP BY r.nombre
ORDER BY total_viajes DESC;
-- Horarios pico (para optimizar frecuencias)
SELECT
t.hora,
SUM(v.num_viajes) AS total_viajes
FROM Viajes v
INNER JOIN Tiempo t ON v.id_tiempo = t.id_tiempo
GROUP BY t.hora
ORDER BY total_viajes DESC;
「Modelos Multidimensionales — Ejercicios 10, 11 y 12」
27 de abril — 1 de mayo de 2026Ejercicio 10 — Cine
¿Qué permite analizar?
- Películas más vistas y en qué horarios.
- Salas con mayor afluencia.
- Preferencias del público por género de película.
- Toma de decisiones: programar más funciones de las películas exitosas y ajustar horarios según la demanda.
CREATE DATABASE CineDW;
USE CineDW;
CREATE TABLE Pelicula (
id_pelicula INT PRIMARY KEY AUTO_INCREMENT,
titulo VARCHAR(150),
genero VARCHAR(50),
duracion_min INT
);
CREATE TABLE Horario (
id_horario INT PRIMARY KEY AUTO_INCREMENT,
hora VARCHAR(10),
dia_semana VARCHAR(20),
mes VARCHAR(20)
);
CREATE TABLE Sala (
id_sala INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(50),
capacidad INT
);
-- Tabla de Hechos: Boletos vendidos
CREATE TABLE Boletos (
id_registro INT PRIMARY KEY AUTO_INCREMENT,
id_pelicula INT, id_horario INT, id_sala INT,
boletos_vendidos INT,
ingreso DECIMAL(10,2),
FOREIGN KEY (id_pelicula) REFERENCES Pelicula(id_pelicula),
FOREIGN KEY (id_horario) REFERENCES Horario(id_horario),
FOREIGN KEY (id_sala) REFERENCES Sala(id_sala)
);
INSERT INTO Pelicula (titulo, genero, duracion_min) VALUES
('El Ultimo Heroe','Accion',130),
('Amor en Roma','Romance',110),
('La Sombra Oscura','Terror',100),
('Mundos Infinitos','Ciencia Ficcion',145),
('Risa Garantizada','Comedia',95);
INSERT INTO Horario (hora, dia_semana, mes) VALUES
('16:00','Lunes','Abril'),('19:00','Lunes','Abril'),
('21:00','Viernes','Abril'),('16:00','Sabado','Abril'),
('19:00','Sabado','Abril'),('21:00','Sabado','Mayo');
INSERT INTO Sala (nombre, capacidad) VALUES
('Sala 1',150),('Sala 2',200),('Sala 3',120);
INSERT INTO Boletos (id_pelicula,id_horario,id_sala,boletos_vendidos,ingreso) VALUES
(1,1,1,120,2400),(1,2,2,180,3600),(4,3,2,195,3900),
(2,4,3,90,1800),(3,5,1,130,2600),(5,5,3,100,2000),
(4,6,2,200,4000),(1,6,1,140,2800),(2,3,3,70,1400);
-- CONSULTAS
-- Peliculas mas vistas (para programar mas funciones)
SELECT
p.titulo, p.genero,
SUM(b.boletos_vendidos) AS total_boletos,
SUM(b.ingreso) AS total_ingreso
FROM Boletos b
INNER JOIN Pelicula p ON b.id_pelicula = p.id_pelicula
GROUP BY p.titulo, p.genero
ORDER BY total_boletos DESC;
-- Horarios con mayor afluencia (para ajustar funciones)
SELECT
h.hora, h.dia_semana,
SUM(b.boletos_vendidos) AS total_boletos
FROM Boletos b
INNER JOIN Horario h ON b.id_horario = h.id_horario
GROUP BY h.hora, h.dia_semana
ORDER BY total_boletos DESC;
Ejercicio 11 — Banco
¿Qué permite analizar?
- Tipos de operaciones más frecuentes (depósito, retiro, transferencia, pago).
- Clientes con mayor actividad bancaria.
- Períodos con mayor volumen de transacciones.
- Toma de decisiones: mejorar canales digitales y reforzar atención en fechas pico.
CREATE DATABASE BancoDW;
USE BancoDW;
CREATE TABLE Cliente (
id_cliente INT PRIMARY KEY AUTO_INCREMENT,
tipo_cliente VARCHAR(30), -- personal, empresarial
edad INT
);
CREATE TABLE TipoOperacion (
id_operacion INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(50) -- deposito, retiro, transferencia, pago
);
CREATE TABLE Fecha (
id_fecha INT PRIMARY KEY AUTO_INCREMENT,
dia INT, mes VARCHAR(20), anio INT
);
-- Tabla de Hechos: Transacciones
CREATE TABLE Transacciones (
id_transaccion INT PRIMARY KEY AUTO_INCREMENT,
id_cliente INT, id_operacion INT, id_fecha INT,
monto DECIMAL(12,2),
num_operaciones INT,
FOREIGN KEY (id_cliente) REFERENCES Cliente(id_cliente),
FOREIGN KEY (id_operacion) REFERENCES TipoOperacion(id_operacion),
FOREIGN KEY (id_fecha) REFERENCES Fecha(id_fecha)
);
INSERT INTO Cliente (tipo_cliente, edad) VALUES
('personal',35),('empresarial',0),('personal',28),
('personal',55),('empresarial',0);
INSERT INTO TipoOperacion (nombre) VALUES
('Deposito'),('Retiro'),('Transferencia'),('Pago de servicio');
INSERT INTO Fecha (dia, mes, anio) VALUES
(1,'Abril',2025),(15,'Abril',2025),(30,'Abril',2025),
(1,'Mayo',2025),(15,'Mayo',2025);
INSERT INTO Transacciones (id_cliente,id_operacion,id_fecha,monto,num_operaciones) VALUES
(1,1,1,5000,3),(1,2,1,2000,2),(2,3,2,50000,10),
(3,4,3,800,5),(4,2,4,3000,4),(5,3,4,120000,15),
(1,4,5,1200,8),(3,1,5,4000,6),(2,1,2,80000,12);
-- CONSULTAS
-- Operaciones mas frecuentes (para mejorar canales)
SELECT
op.nombre AS tipo_operacion,
SUM(t.num_operaciones) AS total_operaciones,
SUM(t.monto) AS monto_total
FROM Transacciones t
INNER JOIN TipoOperacion op ON t.id_operacion = op.id_operacion
GROUP BY op.nombre
ORDER BY total_operaciones DESC;
-- Volumen por mes (para detectar fechas pico)
SELECT
f.mes,
SUM(t.num_operaciones) AS total_operaciones,
SUM(t.monto) AS monto_movido
FROM Transacciones t
INNER JOIN Fecha f ON t.id_fecha = f.id_fecha
GROUP BY f.mes
ORDER BY total_operaciones DESC;
Ejercicio 12 — Plataforma de Streaming
¿Qué permite analizar?
- Contenidos más vistos (series, películas, documentales).
- Horarios de mayor consumo.
- Perfil de usuarios que más consumen.
- Toma de decisiones: recomendar contenido personalizado y mejorar el catálogo según preferencias.
CREATE DATABASE StreamingDW;
USE StreamingDW;
CREATE TABLE Usuario (
id_usuario INT PRIMARY KEY AUTO_INCREMENT,
edad INT,
pais VARCHAR(50),
plan VARCHAR(30) -- basico, estandar, premium
);
CREATE TABLE Contenido (
id_contenido INT PRIMARY KEY AUTO_INCREMENT,
titulo VARCHAR(150),
tipo VARCHAR(30), -- serie, pelicula, documental
genero VARCHAR(50)
);
CREATE TABLE Tiempo (
id_tiempo INT PRIMARY KEY AUTO_INCREMENT,
hora INT,
dia_semana VARCHAR(20),
mes VARCHAR(20)
);
-- Tabla de Hechos: Reproducciones
CREATE TABLE Reproducciones (
id_rep INT PRIMARY KEY AUTO_INCREMENT,
id_usuario INT, id_contenido INT, id_tiempo INT,
num_reproducciones INT,
minutos_vistos INT,
FOREIGN KEY (id_usuario) REFERENCES Usuario(id_usuario),
FOREIGN KEY (id_contenido) REFERENCES Contenido(id_contenido),
FOREIGN KEY (id_tiempo) REFERENCES Tiempo(id_tiempo)
);
INSERT INTO Usuario (edad, pais, plan) VALUES
(22,'Mexico','estandar'),(35,'Mexico','premium'),
(17,'Colombia','basico'),(45,'Mexico','premium'),
(28,'Argentina','estandar');
INSERT INTO Contenido (titulo, tipo, genero) VALUES
('La Casa de Papel','serie','thriller'),
('Avengers Endgame','pelicula','accion'),
('Nuestro Planeta','documental','naturaleza'),
('Dark','serie','misterio'),
('Interstellar','pelicula','ciencia ficcion');
INSERT INTO Tiempo (hora, dia_semana, mes) VALUES
(20,'Lunes','Abril'),(22,'Viernes','Abril'),
(21,'Sabado','Abril'),(15,'Domingo','Abril'),
(20,'Miercoles','Mayo');
INSERT INTO Reproducciones (id_usuario,id_contenido,id_tiempo,num_reproducciones,minutos_vistos) VALUES
(1,1,1,15,600),(2,2,2,8,360),(3,1,3,20,800),
(4,4,4,12,550),(5,3,5,5,200),(1,5,2,10,430),
(2,1,3,18,720),(3,4,4,14,620),(4,2,1,9,400);
-- CONSULTAS
-- Contenidos mas vistos (para mejorar catalogo)
SELECT
c.titulo, c.tipo, c.genero,
SUM(r.num_reproducciones) AS total_reproducciones,
SUM(r.minutos_vistos) AS total_minutos
FROM Reproducciones r
INNER JOIN Contenido c ON r.id_contenido = c.id_contenido
GROUP BY c.titulo, c.tipo, c.genero
ORDER BY total_reproducciones DESC;
-- Horarios de mayor consumo (para recomendar contenido)
SELECT
t.hora,
t.dia_semana,
SUM(r.num_reproducciones) AS total_reproducciones
FROM Reproducciones r
INNER JOIN Tiempo t ON r.id_tiempo = t.id_tiempo
GROUP BY t.hora, t.dia_semana
ORDER BY total_reproducciones DESC;
Apartado adicional — curiosidad sobre OLAP
El término OLAP (Online Analytical Processing) fue propuesto en 1993 por Edgar F. Codd, el mismo investigador que sentó las bases del modelo relacional dos décadas antes. La idea era separar el mundo de las transacciones diarias del mundo del análisis histórico, justo la distinción que se trabajó en estas secuencias entre CRUD y consultas multidimensionales.
moscas moscas
a.
「OLAP vs CRUD / ETL」
4 — 8 de mayo de 2026Mapa conceptual sobre la transición entre dos mundos complementarios: el procesamiento transaccional y el análisis multidimensional.
Resumen del mapa conceptual
| Característica | OLTP / CRUD | OLAP / Multidimensional |
|---|---|---|
| Propósito | Operaciones diarias (captura de datos) | Análisis e inteligencia de negocios |
| Operaciones | CREATE, READ, UPDATE, DELETE | SELECT con SUM, AVG, GROUP BY |
| Estructura | Tablas normalizadas (3FN) | Tabla de hechos + dimensiones (estrella) |
| Rendimiento | Muchas escrituras concurrentes | Lecturas masivas de datos históricos |
| Ejemplo de uso | Registrar una venta en caja | ¿Cuánto se vendió en todo el mes? |
| Tecnología | MySQL, PostgreSQL (transaccional) | Data Warehouse, cubos OLAP |
Concepto ETL (Extract, Transform, Load)
- Extract (Extraer): se obtienen los datos del sistema CRUD/OLTP.
- Transform (Transformar): se limpian, organizan y adaptan al modelo dimensional.
- Load (Cargar): se insertan en el Data Warehouse para análisis.
Flujo completo de arquitectura
Sistema CRUD (OLTP) → Base de datos relacional normalizada → Proceso ETL → Data Warehouse (OLAP) → Reportes y Dashboards
Ejemplo de ETL en SQL
-- Ejemplo de proceso ETL basico
-- (se ejecuta despues de tener datos en el sistema CRUD)
-- Paso 1: Sistema CRUD tiene tablas normalizadas:
-- Clientes(id, nombre)
-- Productos(id, nombre, precio)
-- Ventas(id, id_cliente, fecha)
-- DetalleVentas(id, id_venta, id_producto, cantidad)
-- Paso 2: ETL - Cargar datos al modelo multidimensional
INSERT INTO Hechos_Ventas (id_producto, id_cliente, id_tiempo, cantidad, total)
SELECT
dv.id_producto,
v.id_cliente,
t.id_tiempo,
dv.cantidad,
dv.cantidad * p.precio AS total
FROM DetalleVentas dv
JOIN Ventas v ON dv.id_venta = v.id
JOIN Productos p ON dv.id_producto = p.id
JOIN Dim_Tiempo t ON DATE(v.fecha) = t.fecha_completa;
-- Paso 3: Consulta analitica (OLAP)
SELECT
p.nombre AS producto,
SUM(h.total) AS total_ventas
FROM Hechos_Ventas h
JOIN Dim_Producto p ON h.id_producto = p.id_producto
GROUP BY p.nombre
ORDER BY total_ventas DESC;
Conclusión
- No se convierte el modelo multidimensional en CRUD: son sistemas complementarios.
- CRUD → captura y gestión de datos en tiempo real (OLTP).
- Multidimensional → análisis histórico y toma de decisiones (OLAP).
- La conexión entre ambos se realiza mediante el proceso ETL.
- Error común a evitar: nunca hacer operaciones CRUD directamente sobre el Data Warehouse, ya que genera inconsistencias y bajo rendimiento.
「CRUD en Python con MySQL vía XAMPP」
Ejercicio resuelto electrónicamenteBitácora paso a paso, con configuraciones y código completo, más el ejercicio funcional terminado: un sistema CRUD de consola conectado a MySQL a través de XAMPP.
Paso 1 — Preparación del entorno (XAMPP)
CONFIGURACIÓN INICIAL- Abrir el Panel de Control de XAMPP e iniciar los módulos Apache y MySQL (botones "Start" de ambos servicios).
- Confirmar que el módulo MySQL quede en verde y escuchando en el puerto 3306 (puerto por defecto).
- Entrar a phpMyAdmin desde el navegador en http://localhost/phpmyadmin para crear la base de datos y la tabla de usuarios de forma visual.
- Crear la base de datos crud_python y, dentro de ella, la tabla usuarios (también puede hacerse por código, ver Paso 3).
Paso 2 — Entorno virtual de Python y editor
CONFIGURACIÓN DEL PROYECTO# Crear carpeta del proyecto y entrar en ella mkdir crud_mysql_consola cd crud_mysql_consola # Crear entorno virtual python -m venv venv # Activar entorno virtual (Windows) venv\Scripts\activate # Activar entorno virtual (Mac / Linux) source venv/bin/activate # Abrir el proyecto en Visual Studio Code code .
Con el entorno activo, el prompt de la consola muestra el prefijo (venv), lo que confirma que las librerías que se instalen a continuación quedarán aisladas de las demás instalaciones de Python en el equipo.
Paso 3 — Instalación de dependencias y conexión inicial
mysql-connector-pythonpip install mysql-connector-python
Parámetros de conexión utilizados, acordes a una instalación estándar de XAMPP (usuario root sin contraseña, host local):
import mysql.connector
def conectar():
return mysql.connector.connect(
host="localhost",
user="root",
password="", # XAMPP por defecto no asigna contraseña a root
database="crud_python"
)
Paso 4 — Creación de la base de datos y tabla por código
SCRIPT DE INICIALIZACIÓNCREATE DATABASE IF NOT EXISTS crud_python;
USE crud_python;
CREATE TABLE IF NOT EXISTS usuarios (
id INT AUTO_INCREMENT PRIMARY KEY,
nombre VARCHAR(100) NOT NULL,
correo VARCHAR(100) NOT NULL,
edad INT
);
Paso 5 — Desarrollo de las cuatro funciones CRUD
CREAR · LEER · ACTUALIZAR · ELIMINARCada función abre su propia conexión, ejecuta la sentencia correspondiente y la cierra de forma ordenada para no dejar conexiones abiertas en el servidor MySQL.
import mysql.connector
def conectar():
return mysql.connector.connect(
host="localhost",
user="root",
password="",
database="crud_python"
)
# ---------- CREAR ----------
def crear_usuario(nombre, correo, edad):
conexion = conectar()
cursor = conexion.cursor()
sql = "INSERT INTO usuarios (nombre, correo, edad) VALUES (%s, %s, %s)"
cursor.execute(sql, (nombre, correo, edad))
conexion.commit()
print(f"Usuario '{nombre}' agregado con id {cursor.lastrowid}.")
cursor.close()
conexion.close()
# ---------- LEER ----------
def leer_usuarios():
conexion = conectar()
cursor = conexion.cursor()
cursor.execute("SELECT id, nombre, correo, edad FROM usuarios")
filas = cursor.fetchall()
print("\nID NOMBRE CORREO EDAD")
print("-" * 60)
for fila in filas:
print(f"{fila[0]:<4}{fila[1]:<21}{fila[2]:<26}{fila[3]}")
cursor.close()
conexion.close()
# ---------- ACTUALIZAR ----------
def actualizar_usuario(id_usuario, nombre, correo, edad):
conexion = conectar()
cursor = conexion.cursor()
sql = "UPDATE usuarios SET nombre=%s, correo=%s, edad=%s WHERE id=%s"
cursor.execute(sql, (nombre, correo, edad, id_usuario))
conexion.commit()
if cursor.rowcount:
print(f"Usuario con id {id_usuario} actualizado correctamente.")
else:
print("No se encontro ningun usuario con ese id.")
cursor.close()
conexion.close()
# ---------- ELIMINAR ----------
def eliminar_usuario(id_usuario):
conexion = conectar()
cursor = conexion.cursor()
cursor.execute("DELETE FROM usuarios WHERE id=%s", (id_usuario,))
conexion.commit()
if cursor.rowcount:
print(f"Usuario con id {id_usuario} eliminado.")
else:
print("No se encontro ningun usuario con ese id.")
cursor.close()
conexion.close()
Paso 6 — Menú interactivo de consola (ejercicio completo)
EJECUCIÓN FINAL · main.pyBucle principal que despliega el menú, valida la opción elegida y llama a la función CRUD correspondiente. Este archivo, junto con funciones_crud.py del paso anterior en el mismo directorio, conforma el ejercicio resuelto en su totalidad.
from funciones_crud import (
crear_usuario,
leer_usuarios,
actualizar_usuario,
eliminar_usuario
)
def menu():
while True:
print("\n===== SISTEMA CRUD - USUARIOS (MySQL / XAMPP) =====")
print("1. Crear usuario")
print("2. Ver usuarios")
print("3. Actualizar usuario")
print("4. Eliminar usuario")
print("5. Salir")
opcion = input("Elige una opcion: ")
if opcion == "1":
nombre = input("Nombre: ")
correo = input("Correo: ")
edad = int(input("Edad: "))
crear_usuario(nombre, correo, edad)
elif opcion == "2":
leer_usuarios()
elif opcion == "3":
id_usuario = int(input("ID del usuario a actualizar: "))
nombre = input("Nuevo nombre: ")
correo = input("Nuevo correo: ")
edad = int(input("Nueva edad: "))
actualizar_usuario(id_usuario, nombre, correo, edad)
elif opcion == "4":
id_usuario = int(input("ID del usuario a eliminar: "))
eliminar_usuario(id_usuario)
elif opcion == "5":
print("Saliendo del programa...")
break
else:
print("Opcion no valida, intenta de nuevo.")
if __name__ == "__main__":
menu()
Resumen de la bitácora del video
REFERENCIA POR TIEMPOS — CRUD en Python con MySQL (XAMPP) paso a paso — Consola.MP4| Momento | Contenido |
|---|---|
| 0:18 – 5:52 | Preparación del entorno: arranque del servidor MySQL en XAMPP, creación de base de datos y tabla de usuarios, configuración del entorno virtual de Python y apertura del proyecto en VS Code. |
| 6:42 – 10:57 | Conexión y dependencias: instalación de mysql-connector-python y escritura del código de conexión inicial con usuario root y host local. |
| 11:11 – 28:22 | Desarrollo de las cuatro funciones CRUD: crear (INSERT), leer (SELECT), actualizar (UPDATE) y eliminar (DELETE). |
| 28:36 – 44:08 | Menú interactivo y ejecución: bucle principal que despliega el menú, permite elegir la acción y valida los cambios en tiempo real en consola y en phpMyAdmin. |
El objetivo del video —y de este ejercicio— es manejar bases de datos de forma estructurada sin frameworks, entendiendo la lógica de comunicación entre el backend en Python y el gestor de datos en MySQL.
「Proyecto Integrador — Cierre de Bitácora」
Entrega final del periodo — Febrero a Julio 2026Descripción general del proyecto
Este apartado reúne el proyecto final de la materia, que integra los conocimientos abordados a lo largo de las secuencias 2 a 12: modelado entidad-relación, normalización, bases de datos relacionales, modelos multidimensionales para análisis (OLAP) y procesos ETL, además del ejercicio práctico de conexión entre Python y MySQL mediante XAMPP. Aquí se documenta el desarrollo, las decisiones de diseño y la evidencia correspondiente al cierre del curso.
Evidencias del desarrollo del proyecto
evidencessDocumentos PDF del proyecto
pdf god proM EEEEEEEMEWMMEOW MEOWMOWMEOWMEWOEWO
「Espacios Random / Bitácora Abierta」
wieieieisBitácora abierta
profe lo quiero mucho uwu
erwerewr
23ertyukjhghj
gambare gambare
Señal de prueba
Un pequeño coso raro, sin más función que la curiosidad.