Comandos SQL
A sintaxe que cobre a maior parte das consultas do dia a dia, com atenção aos pontos em que SQL costuma surpreender.
33 itens em 6 seções
Consultar
SELECT coluna FROM tabela WHERE cond- Consulta básica com filtro
ORDER BY coluna DESC NULLS LAST- Ordena decrescente, com os nulos no fim
LIMIT 20 OFFSET 40- Paginação; em SQL Server é OFFSET ... FETCH NEXT
WHERE coluna IS NULL- Nulo só se compara com IS; = NULL nunca é verdadeiro
WHERE coluna IN (1,2,3)- Pertence a uma lista de valores
WHERE nome ILIKE '%ana%'- Busca ignorando maiúsculas no PostgreSQL; em MySQL, LIKE já ignora
Joins
INNER JOIN b ON a.id = b.a_id- Só as linhas com correspondência nos dois lados
LEFT JOIN b ON a.id = b.a_id- Todas as linhas da esquerda; sem par, as colunas da direita vêm nulas
RIGHT JOIN- O espelho do LEFT; raro, porque inverter a ordem das tabelas resolve
FULL OUTER JOIN- Tudo dos dois lados, com nulos onde não há correspondência
CROSS JOIN- Produto cartesiano — toda combinação possível
LEFT JOIN ... WHERE b.id IS NULL- Encontra as linhas da esquerda que não têm par na direita
Agregação
COUNT(*) COUNT(coluna)- O primeiro conta linhas; o segundo ignora nulos
GROUP BY coluna- Agrupa antes de agregar
HAVING COUNT(*) > 1- Filtra depois da agregação; WHERE filtra antes
SUM(x) AVG(x) MIN(x) MAX(x)- Somatório, média, menor e maior
COUNT(DISTINCT coluna)- Valores distintos
COALESCE(coluna, 0)- Primeiro valor não nulo da lista
Funções de janela
ROW_NUMBER() OVER (ORDER BY data)- Numera as linhas sem agrupar
RANK() OVER (PARTITION BY uf ORDER BY valor DESC)- Posição dentro de cada grupo, com empate ocupando a mesma posição
LAG(valor) OVER (ORDER BY data)- Valor da linha anterior; LEAD traz o da próxima
SUM(v) OVER (ORDER BY data ROWS UNBOUNDED PRECEDING)- Soma acumulada
Alterar dados
INSERT INTO t (a,b) VALUES (1,2)- Insere uma linha
INSERT ... ON CONFLICT (id) DO UPDATE SET ...- Upsert no PostgreSQL; em MySQL, ON DUPLICATE KEY UPDATE
UPDATE t SET a = 1 WHERE id = 2- Atualiza; sem WHERE, atualiza a tabela inteira
DELETE FROM t WHERE id = 2- Remove linhas específicas
TRUNCATE TABLE t- Esvazia a tabela; mais rápido que DELETE, mas não dá para reverter em todo banco
BEGIN; ... ROLLBACK;- Teste a alteração dentro de uma transação antes de confirmar
Estrutura e desempenho
EXPLAIN ANALYZE SELECT ...- Mostra o plano de execução com tempo real; é por onde começa toda otimização
CREATE INDEX idx ON t (coluna)- Índice simples
CREATE UNIQUE INDEX ...- Índice que também garante unicidade
ALTER TABLE t ADD COLUMN c TEXT- Acrescenta coluna
CREATE INDEX ... (a, b)- Índice composto; a ordem importa, ele serve para filtros por a e por a+b, não por b sozinho
Perguntas frequentes
- Qual a diferença entre WHERE e HAVING?
- WHERE filtra linhas antes da agregação; HAVING filtra os grupos depois. Por isso não dá para usar COUNT(*) no WHERE — naquele momento a contagem ainda não existe.
- Por que COUNT(*) e COUNT(coluna) dão resultados diferentes?
- Porque COUNT(*) conta linhas e COUNT(coluna) ignora as linhas em que aquela coluna é nula. A diferença entre os dois é exatamente a quantidade de nulos.
- Meu índice existe mas a consulta continua lenta. Por quê?
- Rode EXPLAIN ANALYZE. As causas mais comuns são função aplicada sobre a coluna no WHERE, que impede o uso do índice, e índice composto cuja primeira coluna não aparece no filtro.