SQL (Structured Query Language) es el lenguaje estándar para la gestión y manipulación de bases de datos relacionales. Nacido en los laboratorios de IBM en 1974 y estandarizado por ISO/IEC, SQL sigue siendo el lenguaje universal para interactuar con sistemas de gestión de bases de datos como PostgreSQL, MySQL, SQL Server, Oracle y MariaDB. Su sintaxis declarativa permite definir estructuras de datos, consultar información, modificar registros y administrar servidores con un coste cognitivo muy bajo en relación a la potencia de lo que expresa.
El SQL moderno que se usa en producción hoy combina las cláusulas clásicas (SELECT, JOIN, GROUP BY) con capacidades avanzadas incorporadas al estándar SQL:2016 y SQL:2023 y ampliamente soportadas por PostgreSQL 17+, MySQL 9+ y SQL Server 2022+: funciones ventana con frames sofisticados, CTEs recursivas, operadores JSON nativos sobre JSONB, la sentencia MERGE para upsert atómico, LATERAL JOIN, GENERATED ALWAYS AS para columnas derivadas, tablas temporales con historia auditada y tipos avanzados como arrays, rangos, geografía y vectores para búsqueda semántica.
Este itinerario recorre el lenguaje de principio a fin: desde los fundamentos del modelo relacional y la instalación del entorno hasta la programación procedimental, la concurrencia, la arquitectura multi-tenant con Row-Level Security, la replicación, el Change Data Capture y el DataOps con dbt. Cada módulo se apoya en PostgreSQL como implementación de referencia por ser el motor relacional de código abierto más avanzado y completo del ecosistema actual.
Qué incluye este itinerario
- Introducción y entorno: conceptos de bases de datos, diferencias SQL vs NoSQL, instalación de MySQL y PostgreSQL, categorías DDL/DML, tipos de datos modernos (
JSONB,UUID,TIMESTAMPTZ). - DML y operaciones CRUD: INSERT, SELECT, UPDATE, DELETE y MERGE con ejercicios prácticos de manipulación de datos.
- Consultas con filtros: WHERE con operadores de comparación y lógicos, ORDER BY, DISTINCT, LIMIT y OFFSET para paginación.
- DDL y definición de estructuras: CREATE TABLE, ALTER TABLE, RENAME, DROP,
GENERATED ALWAYS ASy columnas calculadas STORED. - Funciones y agregaciones: funciones de texto, numéricas, de fecha con zona horaria, agregadas, GROUP BY, HAVING y FILTER dentro de agregadas.
- Relaciones entre tablas: claves primarias y foráneas, relaciones Many-to-One, One-to-Many, One-to-One y Many-to-Many con tablas intermedias.
- JOINs y subqueries: INNER JOIN, LEFT/RIGHT JOIN, FULL JOIN, CROSS JOIN, SELF JOIN, LATERAL JOIN y subconsultas correlacionadas.
- Sintaxis avanzada: restricciones de integridad, principios ACID, transacciones, índices, vistas, vistas materializadas, CTEs recursivas, funciones ventana con frames, GROUPING SETS, ROLLUP y CUBE, MERGE INTO, operadores JSON y particionamiento declarativo.
- Programación SQL: variables, control de flujo, procedimientos almacenados, triggers, funciones personalizadas y PL/pgSQL.
- Concurrencia y optimización: MVCC, niveles de aislamiento ISO, locks, deadlocks, EXPLAIN ANALYZE y planes de ejecución.
- Arquitectura y extensiones: Row-Level Security multi-tenant, replicación física y lógica, Point-in-Time Recovery, pgvector para RAG, PostGIS y TimescaleDB.
- Alta disponibilidad y DataOps: Patroni, WAL-G, Change Data Capture con Debezium, outbox pattern, migraciones sin downtime, pgaudit y dbt.
Modelo relacional y entidades
El corazón del diseño SQL es el modelo entidad-relación: cada tabla representa una entidad con una clave primaria estable y las relaciones se materializan como claves foráneas. El diagrama siguiente ilustra un modelo de e-commerce mínimo con las cardinalidades canónicas.
erDiagram
CLIENTE ||--o{ PEDIDO : "realiza"
PEDIDO ||--|{ PEDIDO_LINEA : "contiene"
PRODUCTO ||--o{ PEDIDO_LINEA : "aparece_en"
CATEGORIA ||--o{ PRODUCTO : "agrupa"
CATEGORIA ||--o{ CATEGORIA : "subcategoria"
PEDIDO ||--|| PAGO : "liquida"
CLIENTE {
int id PK
string email UK
string nombre
timestamptz fecha_alta
}
PRODUCTO {
int id PK
string nombre
int categoria_id FK
decimal precio
int stock
}
PEDIDO {
int id PK
int cliente_id FK
timestamptz fecha_creacion
string estado
}
PEDIDO_LINEA {
int id PK
int pedido_id FK
int producto_id FK
int cantidad
decimal precio_unitario
}
Tipos de JOIN en SQL
Los JOINs combinan filas de varias tablas según una condición. La diferencia entre ellos está en cómo tratan las filas sin coincidencia en el otro lado.
flowchart LR
A[Tabla A] --- I[("INNER JOIN<br/>solo coincidencias")]
A --- L[("LEFT JOIN<br/>todas A + coincidencias B")]
A --- R[("RIGHT JOIN<br/>todas B + coincidencias A")]
A --- F[("FULL OUTER JOIN<br/>unión de todo")]
A --- C[("CROSS JOIN<br/>producto cartesiano")]
B[Tabla B] --- I
B --- L
B --- R
B --- F
B --- C
style I fill:#dbeafe,stroke:#3b82f6
style L fill:#dcfce7,stroke:#22c55e
style R fill:#fef3c7,stroke:#f59e0b
style F fill:#fce7f3,stroke:#ec4899
style C fill:#f3e8ff,stroke:#a855f7
Transacciones y principios ACID
Cada bloque BEGIN ... COMMIT se apoya en las cuatro garantías ACID para preservar la integridad de los datos frente a fallos y concurrencia.
flowchart TB
T["BEGIN transaction"] --> A["Atomicity<br/>todo o nada"]
T --> C["Consistency<br/>restricciones siempre válidas"]
T --> I["Isolation<br/>aislada de otras transacciones"]
T --> D["Durability<br/>persistida tras COMMIT"]
A --> OK["COMMIT"]
C --> OK
I --> OK
D --> OK
A --> RB["ROLLBACK si algún paso falla"]
style T fill:#1e293b,stroke:#0f172a,color:#fff
style OK fill:#22c55e,stroke:#15803d,color:#fff
style RB fill:#ef4444,stroke:#991b1b,color:#fff
Tipos de índice y cuándo usarlos
El optimizador elige el plan de ejecución en función de los índices disponibles. Cada tipo de índice resuelve un patrón de consulta distinto.
flowchart LR
Q[Consulta] --> BT["B-tree<br/>igualdad y rango<br/>`WHERE col = ?` y `ORDER BY`"]
Q --> HS["Hash<br/>igualdad exacta<br/>`WHERE col = ?`"]
Q --> FT["Full-text (GIN)<br/>tsvector y tsquery<br/>`@@` y `ts_rank`"]
Q --> JB["GIN sobre JSONB<br/>operadores `@>`, `?`"]
Q --> BR["BRIN<br/>tablas grandes ordenadas<br/>series temporales"]
style BT fill:#dbeafe,stroke:#3b82f6
style HS fill:#dcfce7,stroke:#22c55e
style FT fill:#fef3c7,stroke:#f59e0b
style JB fill:#fce7f3,stroke:#ec4899
style BR fill:#f3e8ff,stroke:#a855f7
CTEs recursivas: jerarquías y grafos
WITH RECURSIVE permite recorrer estructuras jerárquicas (organigramas, categorías anidadas, BOM) con una sola consulta.
flowchart TB
A["Anchor member<br/>SELECT raíz"] --> U[UNION ALL]
R["Recursive member<br/>SELECT hijos JOIN CTE"] --> U
U --> F["CTE final<br/>id, nivel, ruta"]
F --> OUT["SELECT * FROM cte"]
style A fill:#dbeafe,stroke:#3b82f6
style R fill:#dcfce7,stroke:#22c55e
style U fill:#fef3c7,stroke:#f59e0b
style F fill:#fce7f3,stroke:#ec4899
style OUT fill:#1e293b,stroke:#0f172a,color:#fff
Funciones ventana y particiones analíticas
Las window functions calculan métricas sobre un conjunto de filas sin colapsarlas como hace GROUP BY. La cláusula OVER (PARTITION BY ... ORDER BY ...) define el marco de cálculo.
flowchart LR
subgraph IN[Filas de entrada]
F1[cliente=A mes=ene total=100]
F2[cliente=A mes=feb total=200]
F3[cliente=B mes=ene total=150]
F4[cliente=B mes=feb total=50]
end
IN --> P["PARTITION BY cliente<br/>ORDER BY mes"]
P --> OUT[Salida con ventana]
OUT --> S1["A ene 100 acum=100 rank=1"]
OUT --> S2["A feb 200 acum=300 rank=2"]
OUT --> S3["B ene 150 acum=150 rank=1"]
OUT --> S4["B feb 50 acum=200 rank=2"]
style P fill:#1e293b,stroke:#0f172a,color:#fff
Flujo de ejecución de una sentencia SQL
Cada consulta pasa por varias fases antes de devolver resultados. Entender el pipeline ayuda a diagnosticar errores y optimizar el plan.
flowchart LR
Q[Consulta SQL] --> P[Parse<br/>árbol sintáctico]
P --> R[Rewrite<br/>reglas y vistas]
R --> O[Optimize<br/>elige plan de menor coste]
O --> E[Execute<br/>operadores físicos]
E --> OUT[Resultado al cliente]
O -.EXPLAIN ANALYZE.-> PLAN[Plan de ejecución visible]
style P fill:#dbeafe,stroke:#3b82f6
style R fill:#dcfce7,stroke:#22c55e
style O fill:#fef3c7,stroke:#f59e0b
style E fill:#fce7f3,stroke:#ec4899
style OUT fill:#1e293b,stroke:#0f172a,color:#fff
Normalización: 1NF, 2NF y 3NF
El diseño relacional sano sigue las formas normales para evitar redundancia y anomalías de actualización.
flowchart LR
R[Diseño inicial] --> N1["1NF<br/>atomicidad<br/>sin listas ni grupos repetidos"]
N1 --> N2["2NF<br/>dependencia funcional completa<br/>sin dependencias parciales de la PK"]
N2 --> N3["3NF<br/>sin dependencias transitivas<br/>atributo que no depende de no-clave"]
N3 --> OK[Esquema sano y mantenible]
style N1 fill:#dbeafe,stroke:#3b82f6
style N2 fill:#dcfce7,stroke:#22c55e
style N3 fill:#fef3c7,stroke:#f59e0b
style OK fill:#22c55e,stroke:#15803d,color:#fff
Público objetivo
- Desarrolladores backend que necesitan diseñar y consultar bases de datos relacionales en sus aplicaciones.
- Analistas de datos que trabajan con grandes volúmenes de información y necesitan dominar consultas complejas.
- Administradores de bases de datos (DBA) que gestionan servidores PostgreSQL o MySQL en entornos de producción.
- Profesionales de Business Intelligence que construyen informes y dashboards basados en consultas SQL.
- Estudiantes de informática y ciencia de datos que buscan una formación completa en el lenguaje estándar de bases de datos.
- Profesionales IT en transición que quieren incorporar competencias de bases de datos a su perfil.
Prerrequisitos
No se requieren conocimientos previos de programación ni de bases de datos. El itinerario parte desde los conceptos fundamentales y avanza de forma progresiva. Es recomendable tener familiaridad básica con el uso de la terminal o línea de comandos para la instalación del entorno (PostgreSQL o MySQL) y la ejecución de scripts.