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ística | Bases de Datos Relacionales (SQL) | Bases de Datos No Relacionales (NoSQL) |
| Estructura | Tablas con filas y columnas | Documentos, clave-valor, grafos |
| Esquema | Fijo y definido | Flexible, dinámico |
| Consultas | SQL estándar | APIs propias de cada BD |
| Ejemplos | MySQL, PostgreSQL, SQLite | MongoDB, Redis, Firebase |
| Mejor para | Datos estructurados con relaciones | Datos 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
- Las bases de datos relacionales almacenan datos en tablas con filas y columnas, conectadas mediante claves primarias y foráneas.
- CREATE TABLE define la estructura; cada columna tiene un tipo de dato (INT, VARCHAR, DATE, BOOLEAN) y restricciones (NOT NULL, UNIQUE).
- SELECT con WHERE, ORDER BY y LIMIT permite filtrar, ordenar y paginar resultados con precisión.
- Los JOINs combinan datos de múltiples tablas: INNER JOIN solo retorna coincidencias, LEFT JOIN retorna todas las filas de la tabla izquierda.
- GROUP BY con funciones de agregación (COUNT, AVG, SUM, MIN, MAX) genera estadísticas y resúmenes sobre grupos de filas.
- Los índices aceleran las búsquedas dramáticamente en tablas grandes; créalos en columnas usadas frecuentemente en WHERE y JOIN.
- Siempre usa WHERE en UPDATE y DELETE; una operación sin WHERE afecta todos los registros de la tabla.