Programación Web · Capítulo 12

Bases de Datos: Fundamentos de SQL

Aprende a diseñar, consultar y manipular bases de datos relacionales usando el lenguaje estándar de la industria.


1. ¿Qué es una Base de Datos?

Una base de datos es un sistema organizado para almacenar, gestionar y recuperar información de forma eficiente. Sin bases de datos, cada vez que apagas tu computadora perderías todos los datos de tus aplicaciones.

CaracterísticaBases de Datos Relacionales (SQL)Bases de Datos No Relacionales (NoSQL)
EstructuraTablas con filas y columnasDocumentos, clave-valor, grafos
EsquemaFijo y definidoFlexible, dinámico
ConsultasSQL estándarAPIs propias de cada BD
EjemplosMySQL, PostgreSQL, SQLiteMongoDB, Redis, Firebase
Mejor paraDatos estructurados con relacionesDatos variables, alta escalabilidad

2. Conceptos Fundamentales de las Bases Relacionales

Tabla: estructura que almacena datos en filas (registros) y columnas (campos).
Clave Primaria (Primary Key): columna que identifica únicamente cada fila. No puede ser nula ni repetirse.
Clave Foránea (Foreign Key): columna que referencia la clave primaria de otra tabla, estableciendo una relación.

3. Diseño Práctico: Base de Datos de una Escuela

Diseñaremos una base de datos completa para gestionar estudiantes, cursos y calificaciones.

-- Crear la base de datos CREATE DATABASE escuela; USE escuela; -- Tabla de estudiantes CREATE TABLE estudiantes ( id INT PRIMARY KEY AUTO_INCREMENT, nombre VARCHAR(100) NOT NULL, apellido VARCHAR(100) NOT NULL, email VARCHAR(150) UNIQUE NOT NULL, fecha_nac DATE, activo BOOLEAN DEFAULT TRUE, creado_en TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Tabla de cursos CREATE TABLE cursos ( id INT PRIMARY KEY AUTO_INCREMENT, nombre VARCHAR(200) NOT NULL, codigo VARCHAR(20) UNIQUE NOT NULL, creditos INT DEFAULT 3, descripcion TEXT ); -- Tabla de calificaciones (relación muchos-a-muchos) CREATE TABLE calificaciones ( id INT PRIMARY KEY AUTO_INCREMENT, estudiante_id INT NOT NULL, curso_id INT NOT NULL, calificacion DECIMAL(5,2), fecha DATE DEFAULT (CURRENT_DATE), FOREIGN KEY (estudiante_id) REFERENCES estudiantes(id), FOREIGN KEY (curso_id) REFERENCES cursos(id), UNIQUE(estudiante_id, curso_id) -- Un estudiante no puede tener dos notas del mismo curso );

4. INSERT: Insertar Datos

-- Insertar un estudiante INSERT INTO estudiantes (nombre, apellido, email, fecha_nac) VALUES ('Ana', 'García', 'ana.garcia@email.com', '2000-05-15'); -- Insertar múltiples filas a la vez INSERT INTO estudiantes (nombre, apellido, email) VALUES ('Luis', 'Martínez', 'luis.m@email.com'), ('Pedro', 'López', 'pedro.l@email.com'), ('María', 'Rodríguez', 'maria.r@email.com'); -- Insertar cursos INSERT INTO cursos (nombre, codigo, creditos) VALUES ('Matemáticas I', 'MAT101', 4), ('Programación Web', 'PROG201', 3), ('Historia Universal', 'HIST101', 3); -- Insertar calificaciones INSERT INTO calificaciones (estudiante_id, curso_id, calificacion) VALUES (1, 1, 9.5), (1, 2, 8.8), (2, 1, 7.2), (3, 2, 9.1);

5. SELECT: Consultar Datos

-- Seleccionar todos los estudiantes SELECT * FROM estudiantes; -- Seleccionar columnas específicas SELECT nombre, apellido, email FROM estudiantes; -- Con filtro WHERE SELECT nombre, apellido FROM estudiantes WHERE activo = TRUE; -- Múltiples condiciones SELECT nombre, email FROM estudiantes WHERE activo = TRUE AND fecha_nac > '1999-01-01'; -- Ordenar resultados SELECT nombre, apellido FROM estudiantes ORDER BY apellido ASC, nombre ASC; -- Limitar resultados SELECT nombre, email FROM estudiantes ORDER BY creado_en DESC LIMIT 10; -- Buscar con LIKE (patrones) SELECT * FROM estudiantes WHERE email LIKE '%@gmail.com'; -- Termina en @gmail.com -- Operador IN SELECT * FROM cursos WHERE creditos IN (3, 4);

6. UPDATE y DELETE

-- Actualizar un registro específico UPDATE estudiantes SET email = 'ana.nueva@email.com', activo = TRUE WHERE id = 1; -- Actualizar múltiples registros UPDATE calificaciones SET calificacion = calificacion * 1.05 -- Subir 5% todas las notas WHERE curso_id = 1 AND calificacion < 7; -- Eliminar un registro DELETE FROM estudiantes WHERE id = 5; -- CUIDADO: DELETE sin WHERE borra TODOS los registros -- DELETE FROM estudiantes; -- ¡NUNCA hacer sin WHERE en producción!

7. JOINs: Combinar Tablas

Los JOINs son la característica más poderosa del SQL relacional. Permiten combinar datos de varias tablas basándose en una relación.

INNER JOIN: solo filas que tienen coincidencia en ambas tablas.
LEFT JOIN: todas las filas de la tabla izquierda, más las coincidencias de la derecha (NULL si no hay).
RIGHT JOIN: todas las filas de la tabla derecha, más las coincidencias de la izquierda.
-- INNER JOIN: estudiantes con sus calificaciones SELECT e.nombre, e.apellido, c.nombre AS curso, cal.calificacion FROM calificaciones cal INNER JOIN estudiantes e ON cal.estudiante_id = e.id INNER JOIN cursos c ON cal.curso_id = c.id ORDER BY e.apellido, c.nombre; -- LEFT JOIN: todos los estudiantes, tengan o no calificaciones SELECT e.nombre, e.apellido, COUNT(cal.id) AS numero_cursos FROM estudiantes e LEFT JOIN calificaciones cal ON e.id = cal.estudiante_id GROUP BY e.id, e.nombre, e.apellido; -- Resultado: estudiantes sin cursos aparecen con numero_cursos = 0

8. GROUP BY y Funciones de Agregación

-- Promedio de calificaciones por curso SELECT c.nombre AS curso, COUNT(cal.id) AS total_estudiantes, AVG(cal.calificacion) AS promedio, MIN(cal.calificacion) AS minima, MAX(cal.calificacion) AS maxima FROM cursos c LEFT JOIN calificaciones cal ON c.id = cal.curso_id GROUP BY c.id, c.nombre ORDER BY promedio DESC; -- HAVING: filtrar grupos (como WHERE pero para grupos) SELECT estudiante_id, AVG(calificacion) AS promedio FROM calificaciones GROUP BY estudiante_id HAVING AVG(calificacion) >= 8.0; -- Solo estudiantes con promedio >= 8 -- Subquery: estudiante con la calificación más alta SELECT nombre, apellido FROM estudiantes WHERE id = ( SELECT estudiante_id FROM calificaciones ORDER BY calificacion DESC LIMIT 1 );

9. Índices para Rendimiento

-- Sin índice: MySQL escanea CADA fila para encontrar por email -- Con índice: busca en microsegundos como un índice de libro -- Crear índice en columna frecuentemente buscada CREATE INDEX idx_email ON estudiantes(email); CREATE INDEX idx_activo ON estudiantes(activo); -- Índice compuesto (para consultas que filtran por ambas columnas) CREATE INDEX idx_estudiante_curso ON calificaciones(estudiante_id, curso_id); -- Ver qué índices tiene una tabla SHOW INDEX FROM estudiantes; -- EXPLAIN: analizar si una consulta usa índices EXPLAIN SELECT * FROM estudiantes WHERE email = 'ana@email.com';

Resumen del Capítulo