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
| Conceito | O 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.