Jhonatan Pinheiro
Loading page...
Jhonatan Pinheiro
Loading page...
Jhonatan Pinheiro
Loading page...
JOINs, subqueries, VIEWs, transactions and more: 20 techniques that take you beyond basic SELECT.
Passou do básico? Estas 20 técnicas separam quem "sabe SELECT" de quem modela e consulta dados de verdade: JOINs, subconsultas, VIEWs, transações e mais — com exemplos prontos.
Combina linhas de duas tabelas onde a condição casa. Traz só o que existe nas duas.
SELECT p.id, c.nome AS cliente, p.total
FROM pedidos p
INNER JOIN clientes c ON c.id = p.cliente_id;Traz todas as linhas de um lado, mesmo sem correspondência (vira NULL).
-- Todos os clientes, tenham pedidos ou não
SELECT c.nome, p.id AS pedido
FROM clientes c
LEFT JOIN pedidos p ON p.cliente_id = c.id;Traz tudo dos dois lados, casando quando possível. (MySQL não tem nativo — use UNION.)
SELECT c.nome, p.id
FROM clientes c
FULL OUTER JOIN pedidos p ON p.cliente_id = c.id;Útil para hierarquias (ex.: funcionário e seu gerente).
SELECT f.nome AS funcionario, g.nome AS gerente
FROM funcionarios f
LEFT JOIN funcionarios g ON g.id = f.gerente_id;O WHERE filtra linhas; o HAVING filtra grupos (após o GROUP BY).
SELECT cliente_id, COUNT(*) AS qtd
FROM pedidos
GROUP BY cliente_id
HAVING COUNT(*) >= 5;Uma query dentro de outra. Aqui, produtos acima do preço médio.
SELECT nome, preco
FROM produtos
WHERE preco > (SELECT AVG(preco) FROM produtos);Testa se a subconsulta retorna alguma linha. Ótimo para 'quem tem pelo menos um...'.
SELECT c.nome
FROM clientes c
WHERE EXISTS (
SELECT 1 FROM pedidos p WHERE p.cliente_id = c.id
);Empilha resultados de duas queries. UNION remove duplicados; UNION ALL não (e é mais rápido).
SELECT nome FROM clientes_br
UNION ALL
SELECT nome FROM clientes_pt;Um 'if/else' dentro do SELECT. Cria colunas derivadas.
SELECT nome, total,
CASE
WHEN total >= 1000 THEN 'VIP'
WHEN total >= 200 THEN 'Frequente'
ELSE 'Comum'
END AS categoria
FROM pedidos;COALESCE devolve o primeiro não-nulo (ótimo para defaults). NULLIF evita divisão por zero.
SELECT nome, COALESCE(telefone, 'sem telefone') AS contato FROM clientes;
-- Evita erro de divisão por zero
SELECT total / NULLIF(qtd, 0) AS media FROM pedidos;Garante integridade: um pedido sempre aponta para um 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 buscas em colunas muito filtradas. Custa espaço e deixa a escrita um pouco mais lenta.
CREATE INDEX idx_pedidos_cliente ON pedidos(cliente_id);
-- Único (impede duplicados)
CREATE UNIQUE INDEX idx_clientes_email ON clientes(email);Deixe o banco garantir as regras: 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 crescem sozinhos. A sintaxe muda por banco.
-- PostgreSQL
id SERIAL PRIMARY KEY
-- ou BIGSERIAL / GENERATED ALWAYS AS IDENTITY
-- MySQL
id INT AUTO_INCREMENT PRIMARY KEY
-- SQL Server
id INT IDENTITY(1,1) PRIMARY KEYExtraia e calcule com datas. Sintaxe varia por banco.
-- Agora
SELECT CURRENT_TIMESTAMP;
-- Pedidos dos últimos 30 dias (PostgreSQL)
SELECT * FROM pedidos
WHERE data >= CURRENT_DATE - INTERVAL '30 days';
-- Extrair o ano
SELECT EXTRACT(YEAR FROM data) AS ano FROM pedidos;Manipule texto: concatenar, cortar, maiúsculas, tamanho.
SELECT
UPPER(nome) AS maiusculo,
LENGTH(nome) AS tamanho,
SUBSTRING(nome, 1, 3) AS iniciais,
CONCAT(nome, ' <', email, '>') AS contato
FROM clientes;Troca o tipo de um valor (ex.: texto para número).
SELECT CAST('2024-01-15' AS DATE) AS data;
SELECT CAST(preco AS INTEGER) AS preco_inteiro FROM produtos;Uma 'tabela virtual' baseada numa query. Simplifica e padroniza acessos.
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;Insere o resultado de uma query em outra tabela. Ótimo para copiar/arquivar dados.
INSERT INTO clientes_arquivo (id, nome, email)
SELECT id, nome, email
FROM clientes
WHERE ultimo_acesso < '2022-01-01';Agrupa operações: ou todas dão certo (COMMIT), ou nenhuma (ROLLBACK). Essencial para dinheiro.
BEGIN;
UPDATE contas SET saldo = saldo - 100 WHERE id = 1;
UPDATE contas SET saldo = saldo + 100 WHERE id = 2;
COMMIT;
-- Se algo falhar no meio: ROLLBACK; desfaz tudo