Artigo Build·Desenvolvimento·14 min de leitura de leitura

SQL para Iniciantes (2026): Guia Prático com Formatação, Exemplos e Boas Práticas

SQL é a linguagem com maior longevidade em tech: 50 anos depois, continua sendo a forma universal de conversar com bancos de dados. Este guia cobre os comandos essenciais, a ordem lógica que importa, formatação consistente e os erros que iniciantes cometem sem perceber.

Vitor Morais

Por Vitor Morais

Fundador do MochaLabz ·

🗄️

Formate SQL automaticamente

Cole qualquer query e receba formatação padronizada com syntax highlighting.

Usar formatador →

SQL — Structured Query Language — é a linguagem padrão de bancos de dados relacionais desde 1974. Meio século depois, continua sendo o que todo dev, analista e PM precisa entender em algum nível. Este guia parte do zero e cobre o que é essencial para sair lendo e escrevendo SQL em um mês.

Foco no prático: comandos essenciais, ordem lógica que importa, formatação que torna queries legíveis, diferenças entre os principais bancos e os erros clássicos que fazem código novo travar em produção.

Os 6 comandos essenciais

Comandos SQL fundamentais
CritérioO que fazQuando usa
SELECTLê dadosConsultas, relatórios, exports
INSERTAdiciona linhaNovos registros
UPDATEModifica linha existenteEdição de registro
DELETERemove linhaLimpeza, soft-delete via flag
CREATECria tabela, índice, viewSchema inicial, migrations
ALTERModifica estrutura existenteAdicionar coluna, mudar tipo

O SELECT: o comando mais usado

90% do tempo em SQL é escrever SELECT. Anatomia básica:

SELECT coluna1, coluna2 FROM tabela WHERE condicao ORDER BY coluna1 LIMIT 10;

Variações comuns

-- Todas as colunas (evite em produção) SELECT * FROM usuarios; -- Aliases com AS SELECT u.nome AS nome_usuario, u.email AS contato FROM usuarios u; -- Concatenação SELECT nome || ' ' || sobrenome AS nome_completo FROM usuarios; -- Funções comuns SELECT UPPER(nome), LOWER(email), LENGTH(telefone) FROM usuarios; -- Data SELECT NOW() AS agora, CURRENT_DATE AS hoje;

Atenção

SELECT * parece prático, mas em produção é armadilha: retorna colunas que você não usa, aumenta rede, quebra código quando adicionam nova coluna. Liste sempre as colunas explicitamente em queries de produção. Em exploração ad-hoc, tudo bem.

WHERE: filtrando resultados

WHERE filtra linhas antes de retornar. Operadores essenciais:

Operadores no WHERE
CritérioExemploUso
=, !=, <>WHERE id = 42Igualdade
<, >, <=, >=WHERE idade >= 18Comparação
LIKEWHERE nome LIKE 'João%'Busca textual simples
INWHERE status IN ('ativo', 'pendente')Lista de valores
BETWEENWHERE preco BETWEEN 10 AND 100Intervalo
IS NULL / IS NOT NULLWHERE deleted_at IS NULLAusência de valor
AND, OR, NOTWHERE a = 1 AND b = 2Combinações

Dica

LIKE com % no início (LIKE '%João') não usa índice e fica lento. Para busca textual em escala, use full-text search do próprio banco (Postgres tsvector) ou serviço externo (ElasticSearch, Algolia).

ORDER BY e LIMIT

-- Ordenar por uma coluna SELECT * FROM produtos ORDER BY preco DESC; -- Múltiplas colunas com direções diferentes SELECT * FROM pedidos ORDER BY criado_em DESC, total DESC; -- NULLs primeiro ou por último (Postgres) SELECT * FROM usuarios ORDER BY ultimo_login DESC NULLS LAST; -- LIMIT + OFFSET (paginação clássica) SELECT * FROM posts ORDER BY criado_em DESC LIMIT 20 OFFSET 40; -- página 3 com 20 por página

Ordem lógica vs ordem de execução

A ordem que você escreve não é a ordem que o banco executa. Isso explica por que você não pode usar alias do SELECT no WHERE.

Ordem lógica de escrita vs ordem de execução interna
CritérioOrdem de escritaOrdem de execução
1SELECTFROM
2FROMJOIN
3JOINWHERE
4WHEREGROUP BY
5GROUP BYHAVING
6HAVINGSELECT
7ORDER BYORDER BY
8LIMITLIMIT

JOIN: unindo tabelas

JOIN combina linhas de duas tabelas por uma condição. Os tipos principais:

-- INNER JOIN: apenas matches em ambas as tabelas SELECT u.nome, p.total FROM usuarios u INNER JOIN pedidos p ON p.usuario_id = u.id; -- LEFT JOIN: todos da esquerda, com NULL onde não há match SELECT u.nome, p.total FROM usuarios u LEFT JOIN pedidos p ON p.usuario_id = u.id; -- RIGHT JOIN: espelho, raramente usado SELECT u.nome, p.total FROM usuarios u RIGHT JOIN pedidos p ON p.usuario_id = u.id; -- FULL OUTER JOIN: tudo de ambos SELECT u.nome, p.total FROM usuarios u FULL OUTER JOIN pedidos p ON p.usuario_id = u.id;

Agregações: GROUP BY e funções

Para responder perguntas tipo “quantos pedidos por usuário?”, use GROUP BY.

-- Contar pedidos por usuário SELECT usuario_id, COUNT(*) AS total_pedidos, SUM(valor) AS receita_total, AVG(valor) AS ticket_medio, MIN(criado_em) AS primeiro_pedido, MAX(criado_em) AS ultimo_pedido FROM pedidos GROUP BY usuario_id HAVING COUNT(*) >= 5 -- filtra AGREGAÇÃO (não usa WHERE) ORDER BY receita_total DESC LIMIT 10;

Contexto

HAVING filtra após GROUP BY (nas linhas agregadas). WHERE filtra antes(nas linhas originais). Erro comum é tentar usar COUNT(*) no WHERE — retorna erro porque a agregação ainda não aconteceu. Use HAVING.

INSERT, UPDATE, DELETE

-- Inserir uma linha INSERT INTO usuarios (nome, email, criado_em) VALUES ('João', 'joao@exemplo.com', NOW()); -- Inserir várias linhas INSERT INTO usuarios (nome, email) VALUES ('Ana', 'ana@exemplo.com'), ('Bruno', 'bruno@exemplo.com'), ('Carla', 'carla@exemplo.com'); -- Atualizar UPDATE usuarios SET email = 'novo@exemplo.com', atualizado_em = NOW() WHERE id = 42; -- Deletar DELETE FROM usuarios WHERE id = 42; -- Soft delete (recomendado em produção) UPDATE usuarios SET deleted_at = NOW() WHERE id = 42;

Atenção

UPDATE e DELETE sem WHERE atualizam ou deletam todas as linhas da tabela. Muitos bancos (MySQL, Postgres) permitem configurar “safe mode” que exige WHERE. Em produção, execute sempre dentro de transação e teste com SELECT equivalente primeiro.

Boas práticas de formatação

SQL vive em arquivos de migration, notebooks, code review e relatórios. Formatação consistente muda legibilidade dramaticamente.

Estilo comum e recomendado

-- Palavras-chave em MAIÚSCULA, identificadores em minúscula -- Vírgulas ao início da linha (facilita diff em PR) -- Nova linha antes de FROM, WHERE, JOIN, GROUP BY, ORDER BY -- Indentação consistente dentro de subquery SELECT u.id , u.nome , u.email , COUNT(p.id) AS total_pedidos , SUM(p.valor) AS receita_total FROM usuarios u LEFT JOIN pedidos p ON p.usuario_id = u.id WHERE u.criado_em >= '2025-01-01' AND u.status = 'ativo' GROUP BY u.id, u.nome, u.email HAVING COUNT(p.id) >= 3 ORDER BY receita_total DESC LIMIT 50;

Tipos de dados mais comuns

Tipos essenciais em bancos relacionais
CritérioExemploQuando usar
INTEGER / BIGINT42, 1000000IDs, contagens, quantidades
DECIMAL / NUMERIC(p,s)19.99Dinheiro, preços (não use FLOAT)
VARCHAR(n)'João'Textos com limite
TEXTbloco grandeTextos longos sem limite prático
BOOLEANTRUE, FALSEFlags binárias
TIMESTAMP / TIMESTAMPTZ2026-04-17 10:00:00+00Data + hora, com fuso
DATE2026-04-17Só data
UUIDc27a...e88fIDs globais únicos
JSON / JSONB{"k":"v"}Documentos estruturados

Atenção

NUNCA use FLOAT para dinheiro — arredondamento em binário gera erros sutis. Use DECIMAL(10,2) ou armazene em centavos (INTEGER). 0.1 + 0.2 = 0.30000...04 em float é o clássico bug que custa caro em ERP e financeiro.

CREATE TABLE: definindo schema

CREATE TABLE usuarios ( id BIGSERIAL PRIMARY KEY, email VARCHAR(255) NOT NULL UNIQUE, nome VARCHAR(100) NOT NULL, senha_hash VARCHAR(255) NOT NULL, ativo BOOLEAN NOT NULL DEFAULT TRUE, criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW(), atualizado_em TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); CREATE INDEX idx_usuarios_email ON usuarios(email); CREATE INDEX idx_usuarios_ativo ON usuarios(ativo) WHERE ativo = TRUE;

NULL: a dor inevitável

NULL é o conceito mais escorregadio de SQL. Regras práticas:

  • NULL = NULL não retorna TRUE — retorna NULL (unknown).
  • Use IS NULL e IS NOT NULL, não = NULL.
  • Em operações aritméticas, NULL propaga: 5 + NULL = NULL.
  • COALESCE(coluna, 'default') retorna o primeiro não-NULL.
  • Agregações ignoram NULL: COUNT(coluna) não conta linhas com NULL; COUNT(*) conta todas.

Transações: tudo ou nada

Para operações que precisam ser atômicas, use transação:

BEGIN; UPDATE contas SET saldo = saldo - 100 WHERE id = 1; UPDATE contas SET saldo = saldo + 100 WHERE id = 2; -- Se tudo deu certo COMMIT; -- Se algo deu errado -- ROLLBACK;

CTE (WITH): queries legíveis em vez de subqueries aninhadas

WITH pedidos_ativos AS ( SELECT usuario_id, SUM(valor) AS total FROM pedidos WHERE status = 'pago' GROUP BY usuario_id ), top_clientes AS ( SELECT usuario_id, total FROM pedidos_ativos WHERE total > 10000 ) SELECT u.nome, u.email, t.total FROM top_clientes t JOIN usuarios u ON u.id = t.usuario_id ORDER BY t.total DESC;

Diferenças entre PostgreSQL e MySQL

PostgreSQL vs MySQL (pontos mais visíveis para iniciantes)
CritérioPostgreSQLMySQL
String concat||CONCAT()
Limit com offsetLIMIT n OFFSET mLIMIT m, n ou LIMIT n OFFSET m
Auto-incrementSERIAL / GENERATEDAUTO_INCREMENT
BooleanoBOOLEAN nativoTINYINT(1)
JSON queriesJSONB + operadores ricosJSON + funções básicas
Window functionsCompletas desde 2013Disponível desde 8.0

Erros clássicos que iniciantes cometem

  • Esquecer WHERE em UPDATE/DELETE: atualiza ou deleta tudo.
  • Comparar NULL com = : use IS NULL.
  • SELECT * em tabela grande: mata performance e rede.
  • Não usar LIMIT em exploratório: query que trava por 10 minutos retornando 10 milhões de linhas.
  • JOIN sem ON: vira CROSS JOIN, explode linhas.
  • Usar FLOAT para dinheiro: arredondamento quebra cobrança.
  • Hardcode de senha ou dado sensível: logs e backups expõem.
  • Confundir índices UNIQUE com PRIMARY KEY: UNIQUE permite NULL, PK não.

Roteiro dos primeiros 30 dias

Semana 1: fundamentos

Instale PostgreSQL ou use um playground online (DB Fiddle, SQLFiddle). Estude SELECT, WHERE, ORDER BY, LIMIT. Faça 30 queries em um dataset público (Sakila, Northwind, Chinook).

Semana 2: relacionamentos

Pratique JOINs com 2–3 tabelas. Entenda INNER vs LEFT vs FULL. Faça queries que respondam perguntas de negócio reais (top 10 clientes, produto mais vendido por mês).

Semana 3: agregações e CTE

Foque em GROUP BY, HAVING, funções agregadas. Resolva 20 problemas usando CTE (WITH) em vez de subquery aninhada. Aprenda window functions (ROW_NUMBER, RANK, LAG).

Semana 4: performance e schema

Crie tabelas, índices, constraints. Use EXPLAIN para ver planos de execução. Entenda transações e isolamento. Resolva 10 queries lentas e melhore performance em 10x.

SQL em uma frase

SQL parece intimidador pela sintaxe, mas vira segunda natureza após 100 queries escritas. É uma das 3 habilidades com maior ROI em carreira tech: funciona em qualquer empresa que tem banco de dados, que é literalmente toda empresa. Invista os 30 dias iniciais; o retorno acompanha você a vida inteira.

Perguntas frequentes

Qual banco escolher para aprender SQL?+

PostgreSQL é a melhor escolha para aprender em 2026. Open source, padrão da indústria, suporta recursos avançados (JSON, arrays, full-text search, window functions) e a documentação é excelente. MySQL continua muito presente em hospedagens baratas; SQLite é ideal para aprender local sem instalar servidor. Evite começar em bancos comerciais (SQL Server, Oracle) a menos que sua empresa use — sintaxes têm particularidades que confundem iniciante.

Preciso decorar comandos SQL?+

Não. Você precisa entender os 6 comandos essenciais (SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER) e os operadores lógicos. Tudo mais é composição. IDEs modernos (DBeaver, TablePlus, PgAdmin) oferecem autocomplete para funções e sintaxe. Depois de 100 queries escritas com consulta à documentação, você já lembra dos 20% que usa 80% do tempo.

Qual a ordem correta dos comandos em um SELECT?+

A ordem lógica é: SELECT, FROM, JOIN, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT. A ordem de execução interna é diferente (FROM e JOIN primeiro, SELECT penúltimo), o que explica por que você não pode usar alias do SELECT no WHERE. Memorizar a ordem lógica evita erros de sintaxe e facilita leitura de queries complexas.

Devo usar MAIÚSCULA nas palavras-chave SQL?+

É convenção e boa prática, mas tecnicamente SQL é case-insensitive para palavras-chave. SELECT e select funcionam igual. Escrever palavras-chave em MAIÚSCULA (SELECT, WHERE, JOIN) e identificadores em minúscula (usuarios, id_pedido) melhora legibilidade drasticamente em queries longas. Formatadores automáticos aplicam essa convenção.

JOIN ou subquery, qual usar?+

Em geral, JOIN é mais legível e o otimizador do banco costuma executar com mesmo plano. Use subquery quando a lógica de filtro é mais clara nela (ex.: &ldquo;pegar produtos com preço acima da média&rdquo;). CTE com WITH é a forma moderna e mais legível para queries complexas. Evite subqueries aninhadas de 3+ níveis — é sinal de que a lógica precisa de refatoração ou view.

NULL é diferente de vazio?+

Sim, drasticamente. NULL significa &ldquo;ausência de valor&rdquo;; string vazia ('') é um valor — uma string de tamanho zero. Em comparação, NULL = NULL retorna NULL (não TRUE!). Use IS NULL / IS NOT NULL, nunca = NULL. Função COALESCE(valor, 'default') é indispensável para tratar NULLs em queries que alimentam relatórios.

Como formatar SQL de forma consistente?+

Use formatador automático: SQLFluff, pgFormatter, ou o formatador do seu IDE (DBeaver, DataGrip, VSCode extension). Configure em uma convenção única (padrão mais comum: keywords em MAIÚSCULA, alinhamento vertical em SELECTs com múltiplas colunas, nova linha antes de FROM, WHERE, JOIN). Formatação consistente torna code review 10x mais rápido.

Por que queries ficam lentas com muitos dados?+

Principais razões: falta de índice na coluna do WHERE ou JOIN, SELECT * em tabela grande, funções aplicadas à coluna indexada (ex.: WHERE LOWER(nome) = ...), ausência de LIMIT em queries exploratórias, locks por transação longa. Use EXPLAIN para ver o plano de execução antes de acusar o banco. Em 99% dos casos, a query é o problema — não o servidor.

#sql#iniciantes#postgresql#mysql#select#join#formatação sql#banco de dados#cte#índices

Artigos relacionados