Formatting

Uma query bem formatada se lê de cima para baixo, como uma lista de passos. Cada cláusula da linguagem SQL (Structured Query Language · Linguagem de Consulta Estruturada) começa a própria linha, e as colunas ficam indentadas com 2 espaços abaixo dela. A query cresce para baixo e nunca exige que o leitor role a tela para o lado.

Conceitos fundamentais

ConceitoO que é
clause-per-line (uma cláusula por linha)SELECT, FROM, WHERE, JOIN em linhas separadas; cada cláusula é um marco visual
indentation (indentação)2 espaços para colunas, expressões e subqueries; mantém alinhamento sem ambiguidade
vertical layout (layout vertical)A query cresce para baixo a cada cláusula, e a tela nunca precisa rolar para o lado
comma style (estilo de vírgula)Vírgula no final da linha (padrão); vírgula no início preserva diffs limpos
keyword case (caixa de palavra-chave)UPPERCASE para palavras reservadas (SELECT, WHERE); identificadores em PascalCase ou snake_case
trailing whitespace (espaço em branco final)Remover sempre; ruído invisível em diffs
line length (comprimento de linha)Limite de 120 colunas; sqlfluff aplica automaticamente

Cada cláusula começa na própria linha

A query escrita em uma linha só obriga o leitor a varrer o texto atrás de onde termina o SELECT e começa o WHERE. Quebrando por cláusula, cada marco da query fica no início de uma linha e o olho encontra o filtro sem procurar.

❌ Ruim: tudo em uma linha, com as cláusulas misturadas ao conteúdo
SELECT Id, Name, Email FROM Users WHERE Id = 1 AND IsActive = 1

Para achar o filtro, o leitor precisa ler a linha inteira até encontrar a palavra WHERE no meio dela.

✅ Bom: uma cláusula por linha, com as colunas indentadas abaixo dela
SELECT
  Users.Id,
  Users.Name,
  Users.Email
FROM
  Users
WHERE
  Users.Id = 1 AND
  Users.IsActive = 1;

SELECT, FROM e WHERE ficam à esquerda, um por linha. O olho encontra cada um deles sem precisar ler o resto.

Uma query trivial pode ficar em uma linha

A exceção existe para a query que cabe inteira no campo de visão: até 3 campos e até 1 condição. SELECT Users.Id, Users.Name FROM Users WHERE Users.IsActive = 1; se entende de relance, e quebrar isso em oito linhas gasta espaço sem devolver clareza. Passou de 3 campos ou de 1 condição, a query vai para o estilo vertical.

❌ Ruim: inline com 4+ campos ou 2+ condições
SELECT Users.Id, Users.Name, Users.Email, Users.Phone FROM Users WHERE Users.IsActive = 1 AND Users.CreatedAt > '2024-01-01';
✅ Bom: inline só para operações triviais (≤3 campos, ≤1 condição)
SELECT Users.Id, Users.Name FROM Users WHERE Users.IsActive = 1;

DELETE FROM Logs WHERE Logs.Id = 123;

Dois espaços de indentação sob cada cláusula

A coluna indentada mostra que ela pertence ao SELECT logo acima. Sem o recuo, Id e FROM Users ficam na mesma margem e o bloco perde a hierarquia: tudo parece estar no mesmo nível.

❌ Ruim: alinhadas com SELECT, sem indentação
SELECT 
Id, 
Name, 
Email
FROM Users
WHERE Id = 1
AND IsActive = 1
✅ Bom: 2 espaços sob cada cláusula
SELECT
  Users.Id,
  Users.Name,
  Users.Email
FROM
  Users
WHERE
  Users.Id = 1 AND
  Users.IsActive = 1;

JOIN com uma condição cabe em uma linha

Quando o ON tem uma única igualdade, ele fica na mesma linha da tabela que está entrando na query. A linha inteira se lê de uma vez: junte Statuses onde o identificador bate.

❌ Ruim: linha longa misturando JOIN e ON
SELECT Users.Name, Statuses.Description
FROM Users JOIN Statuses ON Users.StatusId = Statuses.Id
WHERE Users.Id = 1;
✅ Bom: ON na mesma linha do JOIN quando há uma única condição
SELECT
  Users.Name,
  Statuses.Description
FROM
  Users
JOIN
  Statuses ON Users.StatusId = Statuses.Id
WHERE
  Users.Id = 1;

JOIN com várias condições abre uma linha por condição

Passando de uma condição, o ON desce para a linha seguinte e cada condição ocupa a própria linha, alinhada com as outras. Assim dá para conferir as regras da junção uma a uma, e acrescentar a próxima condição gera um diff de uma linha.

❌ Ruim: múltiplas condições em linha única
SELECT
  Users.Name,
  Statuses.Description
FROM
  Users
JOIN
  Statuses ON Users.StatusId = Statuses.Id AND Users.IsActive = Statuses.IsActive AND Statuses.Type = 'DEFAULT'
WHERE
  Users.Id = 1;
✅ Bom: uma condição por linha, alinhadas após ON
SELECT
  Users.Name,
  Statuses.Description
FROM
  Users
JOIN
  Statuses
  ON Users.StatusId = Statuses.Id AND
     Users.IsActive = Statuses.IsActive AND
     Statuses.Type = 'DEFAULT'
WHERE
  Users.Id = 1;

Uma condição por linha, com AND ao final

Cada condição do WHERE ocupa uma linha. O AND e o OR ficam no final da linha, e não no começo da linha seguinte. Com o operador no fim, a linha anuncia que a condição continua abaixo, e a leitura segue de cima para baixo sem voltar.

❌ Ruim: AND no início da linha
SELECT
  FootballTeams.Name,
  FootballTeams.ChampionshipsWon
FROM
  FootballTeams
WHERE
  FootballTeams.IsActive = 1
  AND FootballTeams.Country = 'Brazil'
  AND FootballTeams.ChampionshipsWon > 0
ORDER BY
  FootballTeams.ChampionshipsWon DESC;
✅ Bom: AND ao final da linha, fluxo de cima para baixo
SELECT
  FootballTeams.Name,
  FootballTeams.ChampionshipsWon
FROM
  FootballTeams
WHERE
  FootballTeams.IsActive = 1 AND -- active
  FootballTeams.Country = 'Brazil' AND
  FootballTeams.ChampionshipsWon > 0 -- at least one title
ORDER BY
  FootballTeams.ChampionshipsWon DESC;

DoDocs v3.7.0 · Desenvolvido por @thiagocajadev · Baseado no trabalho de pmndrs/docs · Poimandres.