📝 SQL
← Volver

🗄️ SQL — Hoja de Apuntes Completa

Asignatura: Bases de Datos


📌 ¿Qué es SQL?

SQL (Structured Query Language) es el lenguaje estándar para interactuar con bases de datos relacionales. Es un lenguaje declarativo: describes qué quieres obtener, no cómo conseguirlo.

Sistemas de gestión que lo usan

Motor Notas clave
MySQL Open source, muy usado en web
PostgreSQL Open source, el más estándar y potente
SQLite Ligero, sin servidor, ideal para apps
SQL Server Microsoft, entornos empresariales
Oracle DB Empresarial, tiene sintaxis propia

⚠️ Nota: Aunque el estándar SQL es común, cada motor tiene pequeñas diferencias de sintaxis (dialectos).


1️⃣ Categorías del Lenguaje SQL

El lenguaje se divide en 4 sublengprocedures según su propósito:

Categoría Significado ¿Para qué sirve? Comandos principales
DDL Data Definition Language Definir estructura de la BD CREATE, ALTER, DROP, TRUNCATE
DML Data Manipulation Language Manipular datos INSERT, UPDATE, DELETE, SELECT
DCL Data Control Language Control de permisos GRANT, REVOKE
TCL Transaction Control Language Control de transacciones COMMIT, ROLLBACK, SAVEPOINT

2️⃣ Consultas y Filtrado (DML — SELECT)

La anatomía de una consulta SQL completa sigue este orden obligatorio:

SELECT   columnas          -- 1. Qué mostrar
FROM     tabla             -- 2. De dónde
JOIN     otra_tabla ON ... -- 3. Unir tablas (opcional)
WHERE    condicion         -- 4. Filtrar filas
GROUP BY columna           -- 5. Agrupar
HAVING   condicion_grupo   -- 6. Filtrar grupos
ORDER BY columna ASC|DESC  -- 7. Ordenar
LIMIT    n OFFSET m;       -- 8. Paginar

🔑 Regla de oro: El orden de escritura no es el orden de ejecución. La BD ejecuta: FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT.

Palabras clave de selección

Palabra clave ¿Para qué sirve? Ejemplo
SELECT Seleccionar columnas SELECT nombre, edad FROM tabla
SELECT * Seleccionar todo SELECT * FROM usuarios
DISTINCT Eliminar duplicados SELECT DISTINCT ciudad FROM t
LIMIT Limitar filas devueltas LIMIT 10
OFFSET Saltar N filas LIMIT 10 OFFSET 20
AS Alias (renombrar) SELECT nombre AS n FROM t
-- Ejemplo completo de SELECT con alias y DISTINCT
SELECT DISTINCT
    u.nombre    AS nombre_cliente,
    u.ciudad    AS ciudad
FROM usuarios u
LIMIT 5;

3️⃣ Condiciones y Operadores (WHERE)

Operadores de comparación

=       -- Igual
<> / != -- Distinto
>  <    -- Mayor / Menor
>= <=   -- Mayor o igual / Menor o igual

Operadores especiales

Operador ¿Qué hace? Ejemplo
IN Compara contra una lista WHERE id IN (1, 2, 3)
NOT IN Excluye una lista WHERE id NOT IN (4, 5)
BETWEEN Rango inclusivo de valores WHERE edad BETWEEN 18 AND 65
LIKE Búsqueda por patrón de texto WHERE nombre LIKE 'A%'
IS NULL Comprueba si es nulo WHERE telefono IS NULL
IS NOT NULL Comprueba que no sea nulo WHERE email IS NOT NULL
EXISTS Comprueba si subquery devuelve algo WHERE EXISTS (SELECT ...)
ANY / ALL Comparación con subquery WHERE precio > ALL (SELECT ...)

Patrones con LIKE

Patrón Significado Ejemplo
'A%' Empieza por A 'Ana', 'Alex'
'%z' Termina en z 'López'
'%mar%' Contiene "mar" en cualquier posición 'Amara'
'_a_' Exactamente 3 chars, el del medio es a 'bar', 'par'
-- Combinar condiciones con AND, OR, NOT
SELECT * FROM productos
WHERE (precio BETWEEN 10 AND 50)
  AND categoria IN ('ropa', 'calzado')
  AND nombre LIKE '%sport%'
  AND stock IS NOT NULL;

4️⃣ Ordenación y Agrupación

ORDER BY

-- Orden ascendente (por defecto)
SELECT nombre, edad FROM usuarios ORDER BY edad ASC;

-- Orden descendente
SELECT nombre, salario FROM empleados ORDER BY salario DESC;

-- Ordenar por múltiples columnas
SELECT apellido, nombre FROM usuarios ORDER BY apellido ASC, nombre ASC;

GROUP BY y HAVING

🔑 Diferencia clave:
- WHERE filtra antes de agrupar (trabaja sobre filas individuales).
- HAVING filtra después de agrupar (trabaja sobre grupos).

-- Cuántos clientes hay por ciudad
SELECT ciudad, COUNT(*) AS total_clientes
FROM usuarios
GROUP BY ciudad
HAVING COUNT(*) > 5          -- Solo ciudades con más de 5 clientes
ORDER BY total_clientes DESC;

Funciones de agregación

Función ¿Qué hace? Ejemplo
COUNT(*) Cuenta filas COUNT(*)
COUNT(col) Cuenta valores no nulos COUNT(email)
SUM(col) Suma SUM(precio)
AVG(col) Media aritmética AVG(salario)
MAX(col) Valor máximo MAX(fecha_pedido)
MIN(col) Valor mínimo MIN(stock)

5️⃣ JOINs — Unión de Tablas

Los JOINs permiten combinar datos de varias tablas usando una condición de relación (ON).

Tipos de JOIN

Tipo ¿Qué devuelve?
INNER JOIN Solo las filas con coincidencia en ambas tablas
LEFT JOIN Todas las filas de la izquierda + coincidencias
RIGHT JOIN Todas las filas de la derecha + coincidencias
FULL OUTER JOIN Todas las filas de ambas tablas
CROSS JOIN Producto cartesiano (todas las combinaciones posibles)
SELF JOIN Una tabla unida consigo misma

Diagrama conceptual de JOINs

Tabla A    Tabla B
  ●──●──●    ●──●──●

INNER:   solo ●──● (intersección)
LEFT:    A completo + intersección
RIGHT:   B completo + intersección
FULL:    A + B + intersección

Ejemplos prácticos

-- INNER JOIN: pedidos con datos del cliente
SELECT u.nombre, p.fecha, p.total
FROM usuarios u
INNER JOIN pedidos p ON u.id = p.usuario_id;

-- LEFT JOIN: todos los usuarios, hayan pedido o no
SELECT u.nombre, p.total
FROM usuarios u
LEFT JOIN pedidos p ON u.id = p.usuario_id;
-- Los usuarios sin pedidos tendrán NULL en p.total

-- SELF JOIN: empleados con su manager (misma tabla)
SELECT e.nombre AS empleado, m.nombre AS manager
FROM empleados e
LEFT JOIN empleados m ON e.manager_id = m.id;

6️⃣ Subconsultas (Subqueries)

Una subconsulta es una consulta anidada dentro de otra.

-- Subconsulta en WHERE
SELECT nombre FROM usuarios
WHERE id IN (
    SELECT usuario_id FROM pedidos
    WHERE total > 1000
);

-- Subconsulta como tabla derivada (en FROM)
SELECT ciudad, promedio
FROM (
    SELECT ciudad, AVG(salario) AS promedio
    FROM empleados
    GROUP BY ciudad
) AS resumen_ciudades
WHERE promedio > 50000;

-- Subconsulta correlacionada (hace referencia a la consulta exterior)
SELECT nombre, salario
FROM empleados e
WHERE salario > (
    SELECT AVG(salario)
    FROM empleados
    WHERE departamento_id = e.departamento_id
);

7️⃣ Modificación de Datos (DML)

INSERT

-- Insertar una fila
INSERT INTO usuarios (nombre, email, edad)
VALUES ('Ana García', 'ana@email.com', 28);

-- Insertar múltiples filas
INSERT INTO productos (nombre, precio) VALUES
    ('Camiseta', 19.99),
    ('Pantalón', 34.99),
    ('Zapatos', 59.99);

-- Insertar desde otra tabla
INSERT INTO archivo_clientes
SELECT * FROM clientes WHERE fecha_baja IS NOT NULL;

UPDATE

-- Actualizar filas específicas (siempre usar WHERE)
UPDATE usuarios
SET email = 'nuevo@email.com', edad = 29
WHERE id = 42;

-- ⚠️ Sin WHERE actualiza TODAS las filas
UPDATE productos SET iva = 0.21; -- Afecta a TODOS los productos

DELETE

-- Borrar filas específicas
DELETE FROM pedidos WHERE fecha < '2020-01-01';

-- ⚠️ Sin WHERE borra TODOS los registros (la tabla sigue existiendo)
DELETE FROM tabla_temporal;

8️⃣ Definición de Datos (DDL)

CREATE TABLE

CREATE TABLE usuarios (
    id          INT          PRIMARY KEY AUTO_INCREMENT,
    nombre      VARCHAR(100) NOT NULL,
    email       VARCHAR(255) UNIQUE NOT NULL,
    edad        INT          CHECK (edad >= 0 AND edad <= 120),
    ciudad      VARCHAR(50)  DEFAULT 'Madrid',
    creado_en   TIMESTAMP    DEFAULT CURRENT_TIMESTAMP
);

Claves y Restricciones

Restricción ¿Qué garantiza? Ejemplo
PRIMARY KEY Identifica únicamente cada fila id INT PRIMARY KEY
FOREIGN KEY Integridad referencial entre tablas REFERENCES tabla(columna)
UNIQUE No permite valores duplicados email VARCHAR UNIQUE
NOT NULL El campo es obligatorio nombre VARCHAR NOT NULL
CHECK Valida con una condición CHECK (edad >= 18)
DEFAULT Valor por defecto si no se especifica DEFAULT 'activo'
-- Tabla con FOREIGN KEY
CREATE TABLE pedidos (
    id          INT PRIMARY KEY AUTO_INCREMENT,
    usuario_id  INT NOT NULL,
    total       DECIMAL(10,2) NOT NULL,
    fecha       DATE DEFAULT CURRENT_DATE,
    FOREIGN KEY (usuario_id) REFERENCES usuarios(id) ON DELETE CASCADE
);

ALTER y DROP

-- Añadir columna
ALTER TABLE usuarios ADD COLUMN telefono VARCHAR(20);

-- Modificar columna
ALTER TABLE usuarios MODIFY COLUMN nombre VARCHAR(200);

-- Eliminar columna
ALTER TABLE usuarios DROP COLUMN telefono;

-- Eliminar tabla (estructura + datos)
DROP TABLE IF EXISTS tabla_antigua;

-- Vaciar tabla (datos, conserva estructura) — más rápido que DELETE
TRUNCATE TABLE sesiones_temporales;

9️⃣ Funciones Condicionales

Función / Keyword Motor ¿Qué hace? Ejemplo
CASE WHEN Estándar Condicional IF/ELSE CASE WHEN x>1 THEN 'A' ELSE 'B' END
IF() MySQL Condicional simple IF(activo=1, 'Sí', 'No')
COALESCE() Estándar Primer valor no NULL de la lista COALESCE(tel_movil, tel_fijo, 'Sin teléfono')
NULLIF() Estándar Devuelve NULL si los dos son iguales NULLIF(dividendo, 0) (evita división por 0)
IFNULL() MySQL Sustituye NULL por un valor IFNULL(descuento, 0)
DECODE() Oracle Tipo switch DECODE(estado, 1, 'Activo', 0, 'Inactivo')
-- CASE WHEN: categorizar salarios
SELECT nombre, salario,
    CASE
        WHEN salario < 20000 THEN 'Junior'
        WHEN salario BETWEEN 20000 AND 45000 THEN 'Mid'
        WHEN salario > 45000 THEN 'Senior'
        ELSE 'No definido'
    END AS nivel
FROM empleados;

-- COALESCE: teléfono de contacto con fallback
SELECT nombre, COALESCE(tel_movil, tel_fijo, email, 'Sin contacto') AS contacto
FROM clientes;

🔟 Operaciones de Conjuntos

Operador ¿Qué hace? Elimina duplicados
UNION Une resultados de dos consultas ✅ Sí
UNION ALL Une resultados de dos consultas ❌ No
INTERSECT Devuelve filas comunes a ambas consultas ✅ Sí
EXCEPT/MINUS Filas del primero que no están en el segundo ✅ Sí
-- Clientes de Madrid O Barcelona
SELECT nombre FROM clientes WHERE ciudad = 'Madrid'
UNION
SELECT nombre FROM clientes WHERE ciudad = 'Barcelona';

-- Empleados que también son clientes
SELECT email FROM empleados
INTERSECT
SELECT email FROM clientes;

⚠️ Las consultas unidas con UNION deben tener el mismo número de columnas y tipos compatibles.


1️⃣1️⃣ Control de Transacciones (TCL)

Una transacción es un grupo de operaciones que se ejecutan como una unidad atómica (todas o ninguna). Esto garantiza la propiedad ACID.

Propiedades ACID

Propiedad Significado
Atomicidad Todo o nada. Si falla una parte, se revierte todo.
Consistencia La BD pasa de un estado válido a otro estado válido.
Aislamiento Las transacciones concurrentes no se interfieren entre sí.
Durabilidad Una vez confirmada, la transacción persiste aunque el sistema falle.
-- Ejemplo: transferencia bancaria segura
BEGIN TRANSACTION;

    UPDATE cuentas SET saldo = saldo - 500 WHERE id = 1;  -- Débito
    UPDATE cuentas SET saldo = saldo + 500 WHERE id = 2;  -- Crédito

    -- Si algo falla, deshacemos todo
    ROLLBACK;

    -- Si todo va bien, confirmamos
    COMMIT;

-- SAVEPOINT: punto de control intermedio
SAVEPOINT antes_de_actualizar;
UPDATE productos SET precio = precio * 1.10;

ROLLBACK TO antes_de_actualizar;  -- Vuelve al savepoint, no al inicio

1️⃣2️⃣ Control de Permisos (DCL)

-- Dar permisos
GRANT SELECT, INSERT ON base_datos.tabla TO 'usuario'@'host';
GRANT ALL PRIVILEGES ON mi_bd.* TO 'admin'@'localhost';

-- Revocar permisos
REVOKE INSERT ON base_datos.tabla FROM 'usuario'@'host';

1️⃣3️⃣ Optimización y Análisis

EXPLAIN — Ver el plan de ejecución

-- Ver cómo ejecuta la BD la consulta (detectar consultas lentas)
EXPLAIN SELECT * FROM pedidos WHERE usuario_id = 5;

Busca en la salida: type = ALL significa full table scan → necesitas un índice.

Índices

-- Crear índice (acelera búsquedas en esa columna)
CREATE INDEX idx_email ON usuarios(email);

-- Índice compuesto
CREATE INDEX idx_ciudad_edad ON usuarios(ciudad, edad);

-- Eliminar índice
DROP INDEX idx_email ON usuarios;

💡 Regla práctica: Crea índices en columnas que uses en WHERE, JOIN ON u ORDER BY. Demasiados índices ralentizan los INSERT/UPDATE.


📊 Resumen Comparativo: DELETE vs TRUNCATE vs DROP

Operación ¿Borra datos? ¿Borra estructura? ¿Se puede deshacer? ¿Activa triggers?
DELETE ✅ Sí (filas) ❌ No ✅ Sí (con ROLLBACK) ✅ Sí
TRUNCATE ✅ Sí (todos) ❌ No ⚠️ Depende del motor ❌ No
DROP ✅ Sí ✅ Sí ❌ No ❌ No

✅ Resumen en 3 Puntos

  1. SQL se organiza en 4 capas (DDL, DML, DCL, TCL): Cada una controla un aspecto distinto de la base de datos: estructura, datos, permisos y transacciones. Entender qué capa usas en cada momento evita errores graves e irreversibles.

  2. El orden de cláusulas importa y el orden de ejecución es diferente al de escritura: Escribes SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT, pero la BD ejecuta FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT. Esto explica por qué no puedes usar un alias de SELECT en el WHERE.

  3. Los JOINs y las subconsultas son la clave del poder de SQL: Las bases de datos relacionales separan la información a propósito. Los JOINs son el mecanismo para unirla en el momento exacto que necesitas, con control total sobre qué registros incluir (INNER, LEFT, FULL).