Jhonatan Pinheiro
Cargando página...
Jhonatan Pinheiro
Cargando página...
Jhonatan Pinheiro
Cargando página...
JOINs, subconsultas, VIEWs, transacciones y más: 20 técnicas que te llevan más allá del SELECT básico.
¿Ya pasaste lo básico? Estas 20 técnicas separan a quien "sabe SELECT" de quien modela y consulta datos de verdad: JOINs, subconsultas, VIEWs, transacciones y más — con ejemplos listos para usar.
Combina filas de dos tablas donde la condición coincide. Trae solo lo que existe en ambas.
SELECT p.id, c.nome AS cliente, p.total
FROM pedidos p
INNER JOIN clientes c ON c.id = p.cliente_id;Trae todas las filas de un lado, incluso sin correspondencia (que pasa a ser NULL).
-- Todos los clientes, tengan pedidos o no
SELECT c.nome, p.id AS pedido
FROM clientes c
LEFT JOIN pedidos p ON p.cliente_id = c.id;Trae todo de ambos lados, emparejando cuando es posible. (MySQL no lo tiene de forma nativa — usa UNION.)
SELECT c.nome, p.id
FROM clientes c
FULL OUTER JOIN pedidos p ON p.cliente_id = c.id;Útil para jerarquías (por ejemplo, un empleado y su gerente).
SELECT f.nome AS funcionario, g.nome AS gerente
FROM funcionarios f
LEFT JOIN funcionarios g ON g.id = f.gerente_id;El WHERE filtra filas; el HAVING filtra grupos (después del GROUP BY).
SELECT cliente_id, COUNT(*) AS qtd
FROM pedidos
GROUP BY cliente_id
HAVING COUNT(*) >= 5;Una consulta dentro de otra. Aquí, los productos por encima del precio medio.
SELECT nome, preco
FROM produtos
WHERE preco > (SELECT AVG(preco) FROM produtos);Comprueba si la subconsulta devuelve alguna fila. Ideal para 'quién tiene al menos un...'.
SELECT c.nome
FROM clientes c
WHERE EXISTS (
SELECT 1 FROM pedidos p WHERE p.cliente_id = c.id
);Apila los resultados de dos consultas. UNION quita los duplicados; UNION ALL no (y es más rápido).
SELECT nome FROM clientes_br
UNION ALL
SELECT nome FROM clientes_pt;Un 'if/else' dentro del SELECT. Crea columnas derivadas.
SELECT nome, total,
CASE
WHEN total >= 1000 THEN 'VIP'
WHEN total >= 200 THEN 'Frequente'
ELSE 'Comum'
END AS categoria
FROM pedidos;COALESCE devuelve el primer valor no nulo (ideal para valores por defecto). NULLIF evita la división por cero.
SELECT nome, COALESCE(telefone, 'sem telefone') AS contato FROM clientes;
-- Evita el error de división por cero
SELECT total / NULLIF(qtd, 0) AS media FROM pedidos;Garantiza la integridad: un pedido siempre apunta a un cliente que existe.
CREATE TABLE pedidos (
id BIGINT PRIMARY KEY,
cliente_id INTEGER NOT NULL,
total DECIMAL(10,2),
FOREIGN KEY (cliente_id) REFERENCES clientes(id)
);Acelera las búsquedas en columnas muy filtradas. Cuesta espacio y hace la escritura un poco más lenta.
CREATE INDEX idx_pedidos_cliente ON pedidos(cliente_id);
-- Único (impide duplicados)
CREATE UNIQUE INDEX idx_clientes_email ON clientes(email);Deja que la base de datos garantice las reglas: NOT NULL, UNIQUE, CHECK, DEFAULT.
CREATE TABLE produtos (
id INTEGER PRIMARY KEY,
nome VARCHAR(120) NOT NULL,
sku VARCHAR(30) UNIQUE,
preco DECIMAL(10,2) CHECK (preco >= 0),
ativo BOOLEAN DEFAULT TRUE
);IDs que crecen solos. La sintaxis cambia según la base de datos.
-- PostgreSQL
id SERIAL PRIMARY KEY
-- o BIGSERIAL / GENERATED ALWAYS AS IDENTITY
-- MySQL
id INT AUTO_INCREMENT PRIMARY KEY
-- SQL Server
id INT IDENTITY(1,1) PRIMARY KEYExtrae y calcula con fechas. La sintaxis varía según la base de datos.
-- Ahora
SELECT CURRENT_TIMESTAMP;
-- Pedidos de los últimos 30 días (PostgreSQL)
SELECT * FROM pedidos
WHERE data >= CURRENT_DATE - INTERVAL '30 days';
-- Extraer el año
SELECT EXTRACT(YEAR FROM data) AS ano FROM pedidos;Manipula texto: concatenar, cortar, mayúsculas, longitud.
SELECT
UPPER(nome) AS maiusculo,
LENGTH(nome) AS tamanho,
SUBSTRING(nome, 1, 3) AS iniciais,
CONCAT(nome, ' <', email, '>') AS contato
FROM clientes;Cambia el tipo de un valor (por ejemplo, texto a número).
SELECT CAST('2024-01-15' AS DATE) AS data;
SELECT CAST(preco AS INTEGER) AS preco_inteiro FROM produtos;Una 'tabla virtual' basada en una consulta. Simplifica y estandariza los accesos.
CREATE VIEW vw_faturamento_cidade AS
SELECT cidade, SUM(total) AS faturamento
FROM pedidos p
JOIN clientes c ON c.id = p.cliente_id
GROUP BY cidade;
SELECT * FROM vw_faturamento_cidade;Inserta el resultado de una consulta en otra tabla. Ideal para copiar o archivar datos.
INSERT INTO clientes_arquivo (id, nome, email)
SELECT id, nome, email
FROM clientes
WHERE ultimo_acesso < '2022-01-01';Agrupa operaciones: o todas salen bien (COMMIT), o ninguna (ROLLBACK). Esencial cuando hay dinero de por medio.
BEGIN;
UPDATE contas SET saldo = saldo - 100 WHERE id = 1;
UPDATE contas SET saldo = saldo + 100 WHERE id = 2;
COMMIT;
-- Si algo falla a mitad de camino: ROLLBACK; deshace todo