Bases de Datos
12 min

SQL: guía completa desde cero

Trubi

Lucas Trubiano

10 de julio de 2026

SQL: guía completa desde cero

SQL (Structured Query Language) es un lenguaje de consulta de datos estandarizado, diseñado específicamente para gestionar y manipular bases de datos relacionales. Es la herramienta fundamental para almacenar y recuperar datos, actualizar información, administrar bases de datos y establecer relaciones entre distintos conjuntos de datos.

SQL se ha convertido en el estándar internacional para el manejo de bases de datos relacionales, siendo utilizado por la mayoría de los sistemas de gestión de bases de datos (SGBD) como MySQL, PostgreSQL, SQL Server, Oracle, entre otros.

Repositorio de práctica: data_engineering_modern_stack

Estructura básica de SQL

Los comandos SQL se categorizan según su función:

  • DDL (Data Definition Language) para definir estructuras:
    • CREATE: crear nuevos objetos (tablas, bases de datos, vistas)
    • ALTER: modificar la estructura de objetos existentes
    • DROP: eliminar objetos de la base de datos
    • TRUNCATE: eliminar todos los registros de una tabla
    • RENAME: cambiar el nombre de un objeto
  • DML (Data Manipulation Language) para manipular datos:
    • INSERT: agregar nuevos registros a una tabla
    • UPDATE: modificar registros existentes
    • DELETE: eliminar registros de una tabla
  • DQL (Data Query Language) para consultas:
    • SELECT: recuperar datos de una o más tablas
    • FROM: especificar las tablas de origen
    • WHERE: filtrar registros según condiciones
    • GROUP BY: agrupar registros
    • HAVING: filtrar grupos de registros
    • ORDER BY: ordenar resultados

Esta estructura modular permite comenzar con operaciones básicas y avanzar gradualmente hacia funcionalidades más complejas.

Tipos de comandos SQL: DDL, DML, TCL, DQL y DCL

El orden habitual de una consulta con agregación y join sigue esta estructura:

Sintaxis de una consulta SELECT con agregación, filtros y JOIN

Tipos de datos en SQL

Los tipos de datos son fundamentales para definir qué clase de información puede almacenar cada columna en una tabla:

  • Numéricos: INTEGER, DECIMAL, FLOAT para números enteros y decimales.
  • Texto: VARCHAR, CHAR, TEXT para cadenas de caracteres.
  • Fecha/Hora: DATE, TIME, TIMESTAMP para valores temporales.
  • Booleanos: BOOLEAN para valores verdadero/falso.
  • Especiales: BLOB, JSON, XML para datos más complejos.

¿Qué son las bases de datos?

Una base de datos es una colección organizada de información estructurada, almacenada y gestionada de manera sistemática. Permite almacenar grandes cantidades de datos de forma ordenada, acceder rápidamente a la información necesaria, mantener su integridad y seguridad, y actualizarla de manera eficiente.

En el contexto empresarial son fundamentales para la gestión de inventarios, el registro de transacciones, la información de clientes, recursos humanos y el análisis de datos en general.

Esquemas: son contenedores lógicos (como carpetas) que agrupan objetos relacionados (tablas, vistas, etc). Ayudan a organizar y separar los datos por áreas o funciones.

Tablas: son estructuras fundamentales que almacenan los datos en forma de filas (registros) y columnas (campos), como si fuera un Excel. Cada tabla representa una entidad específica, formada por:

  • Columnas: definen los atributos de la entidad, cada una con un tipo de dato específico.
  • Filas: contienen los registros individuales, donde cada fila representa una instancia única de la entidad.

Ejemplo de tabla con filas y columnas

Primary Keys vs. Foreign Keys

Las claves primarias (PK) y foráneas (FK) son fundamentales para establecer relaciones entre tablas:

  • Primary Keys (PK): identifican de manera única cada registro en una tabla, como un DNI para cada persona. No pueden contener valores duplicados ni nulos.
  • Foreign Keys (FK): son referencias a primary keys de otras tablas, creando conexiones entre ellas. Por ejemplo, en una tabla de pedidos, el ID del cliente sería una FK que se relaciona con la PK de la tabla de clientes.

Relación entre tablas mediante primary keys y foreign keys

Las características principales de las bases de datos relacionales son:

  • Estructura tabular: los datos se almacenan en tablas con filas y columnas.
  • Claves primarias y foráneas: permiten establecer relaciones entre tablas.
  • Integridad referencial: mantiene la consistencia entre las relaciones de las tablas.
  • Normalización: organiza los datos de manera eficiente para evitar redundancia.

Algunos ejemplos comunes son PostgreSQL, MySQL, Oracle y SQL Server, cada uno con sus propias características y ventajas.

Tipos de bases de datos

  • Relacionales (SQL): organizan datos en tablas con relaciones predefinidas. Ejemplos: PostgreSQL, MySQL, Oracle Database, SQL Server, SQLite.
  • NoSQL: almacenan datos sin estructura fija, ideal para datos no estructurados y escalabilidad.
    • Clave-valor: pares de clave-valor, ideales para caché y configuraciones simples (Redis, DynamoDB, Cassandra).
    • Orientadas a grafos: especializadas en relaciones complejas entre datos (Neo4j, Amazon Neptune, ArangoDB).
    • En memoria: acceso ultrarrápido desde RAM (Redis, Memcached, Apache Ignite).
    • Familia de columnas: optimizadas para el análisis de grandes volúmenes de datos (Cassandra, HBase, Redshift).
    • Series temporales: diseñadas para datos secuenciales con marca de tiempo (InfluxDB, TimescaleDB, Prometheus).

Ejemplos prácticos

Crear y gestionar tablas

CREATE TABLE permite crear nuevas tablas definiendo su estructura, columnas y tipos de datos:

sql
-- listings: alojamientos o propiedades publicadas en Airbnb.
CREATE TABLE listings (
    id INTEGER PRIMARY KEY,
    name VARCHAR(100),
    host_id INTEGER,
    price DECIMAL(10, 2),
    location VARCHAR(50),
    availability INTEGER
);

-- users: usuarios registrados en Airbnb que reservan alojamientos.
CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100),
    join_date DATE
);

-- reservations: reservas de alojamientos realizadas por los usuarios.
CREATE TABLE reservations (
    id INTEGER PRIMARY KEY,
    listing_id INTEGER,
    user_id INTEGER,
    start_date DATE,
    end_date DATE,
    total_price DECIMAL(10, 2),
    FOREIGN KEY (listing_id) REFERENCES listings(id),
    FOREIGN KEY (user_id) REFERENCES users(id)
);

ALTER TABLE modifica la estructura de una tabla existente:

sql
-- Agregar una columna
ALTER TABLE listings ADD COLUMN rating DECIMAL(3, 2);

DROP TABLE elimina completamente una tabla y todos sus datos:

sql
DROP TABLE listings;

Manipulación de datos

INSERT agrega nuevos registros a una tabla:

sql
-- Insertar un único registro
INSERT INTO listings (id, name, host_id, price, location, availability)
VALUES (1, 'Cozy Apartment Downtown', 101, 120.00, 'New York', 30);

-- Insertar múltiples registros
INSERT INTO listings (id, name, host_id, price, location, availability)
VALUES
    (2, 'Beach House', 102, 200.00, 'Los Angeles', 15),
    (3, 'Mountain Cabin', 103, 150.00, 'Denver', 60);

UPDATE modifica registros existentes:

sql
-- Actualizar el precio de un alojamiento
UPDATE listings
SET price = 130.00
WHERE id = 1;

-- Actualizar múltiples campos
UPDATE listings
SET availability = availability - 5,
    price = price * 1.05
WHERE location = 'New York';

DELETE elimina registros de una tabla:

sql
-- Eliminar un registro específico
DELETE FROM listings
WHERE location = 'Denver';

-- Eliminar todos los registros
DELETE FROM listings;

Consultas básicas

SELECT permite recuperar datos específicos de una tabla:

sql
SELECT name, price, location
FROM listings;

WHERE permite establecer condiciones para filtrar registros:

sql
SELECT name, price
FROM listings
WHERE price > 150;

Los operadores condicionales y lógicos permiten crear filtros más complejos usando AND, OR, IN, BETWEEN, etc.:

sql
SELECT name, location
FROM listings
WHERE availability BETWEEN 10 AND 50
  AND location IN ('New York', 'Los Angeles');

ORDER BY permite ordenar los resultados según una o más columnas:

sql
SELECT name, price
FROM listings
ORDER BY price DESC;

LIMIT permite especificar el número máximo de registros a retornar:

sql
SELECT name, price
FROM listings
ORDER BY price DESC
LIMIT 3;

Consultas avanzadas

Funciones de cadenas de texto

sql
-- Unir el nombre del alojamiento con la ubicación
SELECT CONCAT(name, ' - ', location) AS full_listing_name
FROM listings;

-- Convertir el nombre del alojamiento a mayúsculas
SELECT UPPER(name) AS name_uppercase
FROM listings;

-- Calcular la longitud del nombre del alojamiento
SELECT name, LENGTH(name) AS name_length
FROM listings;

Funciones de fecha y hora

sql
-- Calcular cuántos años lleva listado el alojamiento
SELECT name,
       DATE_PART('year', AGE(CURRENT_DATE, creation_date)) AS years_listed
FROM listings;

-- Extraer el mes de la fecha de creación
SELECT name,
       EXTRACT(MONTH FROM creation_date) AS month_listed
FROM listings;

-- Calcular los días restantes de disponibilidad hasta una fecha específica
SELECT name,
       availability,
       CURRENT_DATE + availability AS last_available_date
FROM listings;

Funciones de agregación

sql
-- Total de alojamientos por ubicación
SELECT location, COUNT(*) AS total_listings
FROM listings
GROUP BY location;

-- Precio promedio por ubicación
SELECT location, AVG(price) AS avg_price
FROM listings
GROUP BY location;

-- Suma total de noches disponibles en todos los alojamientos
SELECT SUM(availability) AS total_nights_available
FROM listings;

-- Precio más alto y más bajo
SELECT MAX(price) AS max_price,
       MIN(price) AS min_price
FROM listings;

Combinado con HAVING es posible filtrar los grupos resultantes de un GROUP BY, y con JOIN (INNER, LEFT, RIGHT, FULL OUTER) es posible combinar información de varias tablas relacionadas mediante sus claves primarias y foráneas.

Postgres

PostgreSQL es un sistema de gestión de bases de datos relacional (RDBMS) de código abierto y orientado a objetos. Desarrollado originalmente en la Universidad de California en Berkeley, se ha convertido en uno de los sistemas de bases de datos más populares y confiables del mundo.

Características principales:

  • Soporte completo para ACID (Atomicidad, Consistencia, Aislamiento, Durabilidad)
  • Capacidades avanzadas de replicación y alta disponibilidad
  • Extensibilidad mediante funciones y procedimientos almacenados en múltiples lenguajes
  • Soporte nativo para tipos de datos JSON y XML
  • Herencia de tablas y particionamiento
  • Funciones de ventana y CTEs (Common Table Expressions)
  • Potente sistema de índices (B-tree, Hash, GiST, SP-GiST, GIN, BRIN)

Ventajas: gratuito y de código abierto, excelente cumplimiento de estándares SQL, gran capacidad de extensión, sólido soporte para transacciones concurrentes y comunidad activa.

Desventajas: puede ser más lento en operaciones simples comparado con MySQL, mayor consumo de recursos en configuraciones por defecto y curva de aprendizaje más pronunciada para administración.

Tip: la elección del RDBMS adecuado depende de tus necesidades específicas, presupuesto y casos de uso. PostgreSQL destaca especialmente en aplicaciones que requieren integridad de datos, operaciones complejas y extensibilidad.

Instalación de PostgreSQL y pgAdmin con Docker

bash
# Descargar la imagen de PostgreSQL
docker pull postgres:latest

# Crear y ejecutar el contenedor
docker run --name postgres-db -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d postgres
bash
# Descargar la imagen de pgAdmin
docker pull dpage/pgadmin4

# Crear y ejecutar el contenedor
docker run --name pgadmin -e PGADMIN_DEFAULT_EMAIL=usuario@dominio.com -e PGADMIN_DEFAULT_PASSWORD=admin -p 80:80 -d dpage/pgadmin4

También se pueden gestionar ambos servicios con Docker Compose:

yaml
version: '3.8'
services:
  postgres:
    image: postgres:latest
    container_name: postgres-db
    environment:
      POSTGRES_PASSWORD: mysecretpassword
    ports:
      - "5432:5432"
    volumes:
      - postgres-data:/var/lib/postgresql/data

  pgadmin:
    image: dpage/pgadmin4
    container_name: pgadmin
    environment:
      PGADMIN_DEFAULT_EMAIL: usuario@dominio.com
      PGADMIN_DEFAULT_PASSWORD: admin
    ports:
      - "80:80"
    depends_on:
      - postgres

volumes:
  postgres-data:
bash
docker-compose up -d

Para conectar pgAdmin con PostgreSQL: accedé a http://localhost:80, iniciá sesión con las credenciales configuradas y creá un nuevo servidor con host postgres (si usás Docker Compose) o localhost, puerto 5432, usuario postgres y la contraseña configurada.

Tip: cambiá las contraseñas por unas seguras en producción y nunca compartas credenciales en control de versiones.

SQLite

SQLite es un sistema de gestión de bases de datos relacional contenido en una biblioteca C. A diferencia de otros sistemas, no es un motor cliente-servidor, sino que se integra directamente en el programa final.

Características principales:

  • Base de datos contenida en un único archivo
  • No requiere configuración ni servidor
  • Transaccional (ACID)
  • Alta portabilidad
  • Código abierto
  • Sin necesidad de administración

Ventajas: configuración cero, portátil (toda la base de datos en un solo archivo), excelente para aplicaciones embebidas, ideal para desarrollo y pruebas, no requiere un proceso servidor separado y mínimo uso de recursos.

Desventajas: no adecuado para aplicaciones multiusuario grandes, limitaciones en la concurrencia, sin gestión de usuarios nativa y limitaciones en el tamaño de la base de datos.

CaracterísticaSQLitePostgreSQLMySQL
TipoArchivo únicoCliente-ServidorCliente-Servidor
ConfiguraciónNingunaAltaAlta
EscalabilidadBajaAltaAlta
Uso idealApps locales, desarrollo, pruebasApps empresarialesApps web medianas

Instalación

Para más información consultá la guía de sqlite.org.

macOS:

bash
# Usando Homebrew
brew install sqlite3

# Verificar instalación
sqlite3 --version

Linux:

bash
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install sqlite3

# Fedora
sudo dnf install sqlite

Windows: descargá el paquete precompilado desde sqlite.org, extraé los archivos, agregá la ruta al PATH del sistema e instalá DB Browser for SQLite si querés una interfaz gráfica.

Uso básico

sql
-- Crear una nueva base de datos
sqlite3 mydatabase.db

-- Crear una tabla
CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    email TEXT UNIQUE
);

-- Insertar datos
INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com');

-- Consultar datos
SELECT * FROM users;

-- Salir
.quit

Comandos útiles: .tables (muestra todas las tablas), .schema (muestra el esquema), .mode column (formatea la salida en columnas), .headers on (muestra encabezados) y .backup [archivo] (crea una copia de seguridad).

Mejores prácticas

Tip: usá transacciones para operaciones múltiples. Garantizan que varias operaciones se completen como una unidad atómica.

sql
BEGIN TRANSACTION;
INSERT INTO usuarios (nombre) VALUES ('Juan');
UPDATE saldo SET cantidad = cantidad - 100 WHERE usuario_id = 1;
COMMIT;

Tip: implementá índices para las consultas frecuentes. Mejoran significativamente el rendimiento de las búsquedas.

sql
-- Crear un índice en la columna email
CREATE INDEX idx_usuarios_email ON usuarios(email);

-- Consulta que se beneficiará del índice
SELECT * FROM usuarios WHERE email = 'juan@example.com';

Las columnas más comunes para crear índices son: claves primarias (automáticamente indexadas en SQLite), columnas de búsqueda frecuente, claves foráneas (para optimizar JOINs) y columnas usadas en ORDER BY o WHERE. Es importante no sobre-indexar, ya que cada índice ocupa espacio adicional en disco y ralentiza las operaciones de escritura.

Tip: realizá copias de seguridad regulares. SQLite ofrece comandos simples para respaldar la base de datos.

sql
.backup 'backup_20250118.db'
-- O desde la línea de comandos
sqlite3 basededatos.db ".backup 'backup_20250118.db'"

Tip: mantené la base de datos lo más pequeña posible, eliminando datos innecesarios y optimizando el espacio.

sql
-- Vaciar espacio no utilizado
VACUUM;

-- Eliminar registros antiguos
DELETE FROM tabla WHERE fecha < date('now', '-30 days');

Tip: usá sentencias preparadas para consultas parametrizadas. Previenen inyección SQL y mejoran el rendimiento.

python
# Ejemplo en Python con sqlite3
cursor.execute("""
    INSERT INTO usuarios (nombre, email)
    VALUES (?, ?)
""", ('Juan', 'juan@example.com'))

SQLite es una excelente opción para aplicaciones pequeñas, ambientes de desarrollo y pruebas, y cualquier situación donde la simplicidad y la portabilidad sean prioritarias sobre la escalabilidad y las características avanzadas de los sistemas de bases de datos más grandes.