FullStackJS Camp
Módulo 5·teoria·4h
Objetivos de aprendizaje
  • Comprender qué es una base de datos relacional y el modelo de tablas.
  • Distinguir SQL de los motores de bases de datos (MySQL, PostgreSQL).
  • Escribir consultas SELECT básicas con WHERE, ORDER BY y LIMIT.
  • Usar funciones de agregación: COUNT, SUM, AVG, MIN, MAX.
  • Combinar tablas con JOIN.

Introducción a SQL

SQL (Structured Query Language) es el lenguaje estándar para comunicarse con bases de datos relacionales. Lo usan MySQL, PostgreSQL, SQL Server, SQLite y Oracle — aprender SQL en uno es transferible a todos.


El modelo relacional

Una base de datos relacional organiza la información en tablas (también llamadas relaciones):

code
┌─────────────────────────────────────────────────────────┐
│ Tabla: usuarios                                          │
├──────────┬──────────┬─────────────────────┬─────────────┤
│ user_id  │ nombre   │ correo              │ saldo       │
│ (PK)     │          │                     │             │
├──────────┼──────────┼─────────────────────┼─────────────┤
│ 1        │ Juan     │ juan@example.com    │ 50000.00    │
│ 2        │ Ana      │ ana@example.com     │ 120000.00   │
│ 3        │ Pedro    │ pedro@example.com   │ 8000.00     │
└──────────┴──────────┴─────────────────────┴─────────────┘

Conceptos fundamentales:

ConceptoDefinición
TablaColección de filas del mismo tipo de entidad
Fila / registroUna instancia de esa entidad
Columna / campoUn atributo de cada fila
Clave Primaria (PK)Identificador único e irrepetible de cada fila
Clave Foránea (FK)Columna que referencia la PK de otra tabla

SQL vs Motor de base de datos

SQLMotor (RDBMS)
El lenguaje para escribir consultasEl programa que ejecuta esas consultas
Estándar ISOMySQL, PostgreSQL, SQL Server, SQLite
SELECT * FROM usuariosSabe cómo leer los archivos de disco

En este módulo usamos MySQL para la demo (Alke Wallet). Los conceptos son idénticos en PostgreSQL — las diferencias se señalan cuando aplica.


Tipos de datos principales

TipoUsoEjemplo
INT / BIGINTNúmeros enterosuser_id, edad
DECIMAL(12,2)Decimales exactos (dinero)saldo, precio
VARCHAR(n)Texto variable (máximo n chars)nombre, correo
TEXTTexto largo sin límitedescripcion
DATEFecha (sin hora)2024-10-01
DATETIMEFecha y hora2024-10-01 10:30:00
BOOLEANVerdadero/falsoactivo
ENUM(...)Lista fija de valores'pendiente','pagado'

SELECT — Consultar datos

Básico

sql
-- Todos los registros y columnas
SELECT * FROM usuarios;

-- Columnas específicas
SELECT nombre, correo, saldo
FROM usuarios;

-- Con alias (apodo de columna)
SELECT nombre AS "Nombre del usuario",
       saldo  AS "Saldo disponible"
FROM usuarios;

WHERE — Filtrar filas

sql
-- Igual
SELECT * FROM usuarios WHERE user_id = 2;

-- Comparadores: = < > <= >= !=
SELECT * FROM usuarios WHERE saldo > 10000;

-- AND / OR
SELECT * FROM usuarios
WHERE saldo > 5000
  AND saldo < 100000;

-- IN (lista de valores)
SELECT * FROM usuarios
WHERE user_id IN (1, 3);

-- LIKE — búsqueda de texto
-- % = cualquier cantidad de caracteres
-- _ = exactamente un caracter
SELECT * FROM usuarios
WHERE nombre LIKE 'J%';    -- nombres que empiezan con J

-- IS NULL / IS NOT NULL
SELECT * FROM productos
WHERE descripcion IS NULL;

ORDER BY y LIMIT

sql
-- Ordenar ascendente (ASC por defecto)
SELECT * FROM usuarios
ORDER BY saldo DESC;   -- de mayor a menor saldo

-- Limitar resultados (paginación)
SELECT * FROM usuarios
ORDER BY user_id
LIMIT 10 OFFSET 0;     -- primeros 10 (página 1)

-- LIMIT 10 OFFSET 10; -- página 2

Funciones de agregación

sql
-- Contar filas
SELECT COUNT(*) AS total_usuarios FROM usuarios;

-- Sumar
SELECT SUM(saldo) AS saldo_total FROM usuarios;

-- Promedio
SELECT AVG(saldo) AS saldo_promedio FROM usuarios;

-- Mínimo y máximo
SELECT MIN(saldo) AS menor, MAX(saldo) AS mayor
FROM usuarios;

GROUP BY — Agrupar y agregar

sql
-- Total enviado por cada remitente
SELECT sender_user_id,
       COUNT(*)         AS total_transacciones,
       SUM(valor)       AS monto_enviado
FROM transacciones
GROUP BY sender_user_id
ORDER BY monto_enviado DESC;

-- HAVING: filtrar sobre el resultado del GROUP BY
-- (WHERE filtra antes de agrupar, HAVING filtra después)
SELECT sender_user_id,
       SUM(valor) AS monto_enviado
FROM transacciones
GROUP BY sender_user_id
HAVING SUM(valor) > 10000;

JOIN — Combinar tablas

sql
-- Base de datos Alke Wallet:
-- usuarios (user_id, nombre, correo, saldo)
-- transacciones (transaction_id, sender_user_id, receiver_user_id, valor, transaction_date)

-- INNER JOIN: solo filas que coinciden en ambas tablas
SELECT
  u.nombre           AS remitente,
  t.valor,
  t.transaction_date
FROM transacciones t
  INNER JOIN usuarios u ON u.user_id = t.sender_user_id
ORDER BY t.transaction_date DESC;
Tipo de JOINRetorna
INNER JOINSolo filas con coincidencia en ambas tablas
LEFT JOINTodas las filas de la tabla izquierda + coincidencias de la derecha (NULL si no hay)
RIGHT JOINTodas las filas de la tabla derecha + coincidencias de la izquierda
sql
-- LEFT JOIN: todos los usuarios, incluso los que nunca enviaron dinero
SELECT
  u.nombre,
  COUNT(t.transaction_id) AS transacciones_enviadas
FROM usuarios u
  LEFT JOIN transacciones t ON t.sender_user_id = u.user_id
GROUP BY u.user_id, u.nombre
ORDER BY transacciones_enviadas DESC;

Consultas con múltiples JOINs

sql
-- Quién envió y quién recibió, con nombres
SELECT
  e.nombre       AS remitente,
  r.nombre       AS receptor,
  t.valor,
  t.transaction_date
FROM transacciones t
  JOIN usuarios e ON e.user_id = t.sender_user_id
  JOIN usuarios r ON r.user_id = t.receiver_user_id
ORDER BY t.transaction_date;

Script base: Alke Wallet

Usa este script para crear la base de datos de práctica del módulo:

sql
-- 1) Crear y seleccionar la base de datos
DROP DATABASE IF EXISTS alke_wallet;
CREATE DATABASE alke_wallet CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE alke_wallet;

-- 2) Tabla usuarios
CREATE TABLE usuarios (
  user_id    INT AUTO_INCREMENT PRIMARY KEY,
  nombre     VARCHAR(80)    NOT NULL,
  correo     VARCHAR(120)   NOT NULL UNIQUE,
  contrasena VARCHAR(120)   NOT NULL,
  saldo      DECIMAL(12,2)  NOT NULL DEFAULT 0,
  created_at DATE           NOT NULL DEFAULT (CURRENT_DATE)
);

-- 3) Tabla monedas
CREATE TABLE monedas (
  currency_id     INT AUTO_INCREMENT PRIMARY KEY,
  currency_name   VARCHAR(60) NOT NULL,
  currency_symbol VARCHAR(10) NOT NULL
);

-- 4) Tabla transacciones
CREATE TABLE transacciones (
  transaction_id   INT AUTO_INCREMENT PRIMARY KEY,
  sender_user_id   INT           NOT NULL,
  receiver_user_id INT           NOT NULL,
  valor            DECIMAL(12,2) NOT NULL,
  transaction_date DATETIME      NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_sender   FOREIGN KEY (sender_user_id)   REFERENCES usuarios(user_id),
  CONSTRAINT fk_receiver FOREIGN KEY (receiver_user_id) REFERENCES usuarios(user_id)
);

-- 5) Datos de prueba
INSERT INTO usuarios (nombre, correo, contrasena, saldo, created_at) VALUES
  ('Juan',  'juan@example.com',  '1234', 50000,  '2019-12-15'),
  ('Ana',   'ana@example.com',   '1234', 120000, '2021-06-10'),
  ('Pedro', 'pedro@example.com', '1234', 8000,   '2023-03-05');

INSERT INTO monedas (currency_name, currency_symbol) VALUES
  ('Peso chileno', 'CLP'),
  ('Dólar',        'USD'),
  ('Euro',         'EUR');

INSERT INTO transacciones (sender_user_id, receiver_user_id, valor, transaction_date) VALUES
  (1, 2, 15000, '2024-10-01 10:00:00'),
  (2, 1, 25000, '2024-10-02 12:30:00'),
  (3, 1, 4000,  '2024-10-03 09:15:00');