Todos os artigos
74 artigos · atualizado semanalmente Veja nossas Ferramentas
Todos os artigos
Dicas

SQL sem formatação é dívida técnica que você paga na revisão de código

SQL mal formatado não quebra nada — mas esconde bugs, aumenta o tempo de revisão e vira template ruim. Como padronizar sem cerimônia.

COVER · Dicas

Você abre o PR e a query tem 40 colunas numa linha só. Você sabe o que ela faz. O revisor não. Você vai explicar nos comentários, o revisor vai aprovar sem entender, e daqui a seis meses ninguém vai lembrar por que tem um LEFT JOIN ali.

Esse post é sobre por que SQL mal formatado é dívida técnica real — e como resolver sem cerimônia.


O que SQL ilegível esconde

Coloque as duas queries abaixo uma do lado da outra:

select u.id, u.name, u.email, o.total, o.created_at from users u left join orders o on u.id = o.user_id where u.active = true and o.total > 100 order by o.created_at desc limit 50
SELECT
  u.id,
  u.name,
  u.email,
  o.total,
  o.created_at
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE
  u.active = true
  AND o.total > 100
ORDER BY o.created_at DESC
LIMIT 50

O resultado é idêntico. A segunda leva três segundos a mais para escrever e meia hora a menos para revisar.

A diferença não é estética. Na primeira versão, o LEFT JOIN some no meio do ruído — e LEFT JOIN importa. Significa que a query retorna usuários sem pedidos também, com o.total como NULL. Se o negócio esperava apenas usuários com pedidos acima de R$ 100, esse é um bug. Na segunda versão, a intenção fica visível imediatamente: você vê o LEFT JOIN, para, e pergunta "é isso mesmo que queremos aqui?"

Formatação não é sobre deixar bonito. É sobre tornar a lógica auditável.

As convenções que importam na prática

Não existe um padrão universal de SQL, mas algumas escolhas reduzem atrito de forma consistente:

Keywords em maiúsculo. SELECT, FROM, WHERE, JOIN — maiúsculo. Colunas e tabelas em minúsculo. Isso cria contraste visual imediato entre estrutura e dado, sem precisar de syntax highlighting.

Uma coluna por linha no SELECT. Quando a lista de colunas passa de três, uma por linha. Facilita diff no git, facilita comentar uma coluna específica no PR, facilita adicionar ou remover sem tocar nas outras linhas.

Condições do WHERE alinhadas. Cada condição na própria linha, com AND e OR no início (não no final). O motivo é simples: comentar uma condição no início da linha é mais direto do que caçar o AND no final da linha anterior.

WHERE
  u.active = true
  AND o.total > 100
  -- AND o.status = 'paid'  ← fácil de comentar em debug

JOINs explícitos, nunca vírgula no FROM. FROM users, orders WHERE users.id = orders.user_id é válido em todo dialeto SQL. É também a forma mais rápida de acidentalmente produzir um produto cartesiano quando você esquece a condição de join. Use JOIN explícito, sempre.

O problema de padronizar manualmente

O obstáculo real não é saber as convenções — é aplicá-las consistentemente num time onde cada pessoa tem um editor diferente, um plugin diferente, e um nível diferente de paciência para formatação manual.

A solução é automatizar. Para queries que vão entrar em código (migrations, queries em ORM raw, scripts), o ideal é ter um formatter no pipeline. Para o dia a dia — colar uma query num ticket, compartilhar num Slack, revisar antes de rodar num banco de produção — eu uso o Formatador SQL direto no browser. Cola a query, escolhe o dialeto (PostgreSQL, MySQL, T-SQL), e já sai formatada. Útil especialmente quando você recebe uma query de outra pessoa e precisa entendê-la antes de qualquer coisa.

Formatação em migration é diferente

Uma observação que vale separar: SQL em migration file tem regras adicionais além da formatação.

Migrations são lidas por humanos na revisão e por máquinas na execução — e raramente são revertidas depois de aplicadas em produção. Isso significa que cada migration precisa ser autoexplicativa sem contexto externo. Comentário inline é obrigatório quando a query tem alguma lógica não óbvia:

-- Remove duplicate rows keeping the most recent entry per user_id
-- Safe to run: no FK references this table
DELETE FROM user_sessions
WHERE id NOT IN (
  SELECT MAX(id)
  FROM user_sessions
  GROUP BY user_id
);

Formatação limpa + comentário de intenção = migration que qualquer pessoa do time consegue auditar seis meses depois sem perguntar nada no Slack.

Legibilidade é uma decisão de time, não de pessoa

SQL ilegível quase nunca é resultado de preguiça — é resultado de contexto. A pessoa escreveu direto no console, testou, copiou e colou. Funciona. Ninguém vai refatorar o que já funciona.

O problema é quando esse padrão se replica. Uma query sem formatação vira template para a próxima. Daqui a um ano, o codebase tem cinquenta queries que ninguém consegue revisar em menos de dez minutos cada.

A mudança não precisa ser radical: formatter automático no pre-commit para arquivos .sql, convenção documentada no README, e o hábito de formatar antes de compartilhar. O custo é baixo. O retorno aparece na primeira vez que alguém pega um bug numa query de review em vez de em produção.

HT
Autor
Hugo Tanaka
Japonês-brasileiro de segunda geração, cresceu vendo o pai debugar planilhas de logística em BASIC. Desenvolvedor full-stack com foco em tooling e DX — o papel que finalmente uniu código, escrita e obsessão por produtividade num lugar só. Escreve para quem já sabe programar e quer resolver um problema agora.
Ver perfil