Fazer o SQL rodar é uma coisa. Fazer outros humanos o lerem é outra. Formatar é a segunda, não a primeira. O hábito de formatação da maioria dos desenvolvedores é “pressionar Tab manualmente para ajustar indentação no editor” — isso resolve 30% do problema. Os 70% restantes (diferenças de dialeto, capitalização de palavras-chave, ponto e vírgula dentro de strings, comentários sendo engolidos, CTE não recursivo, subconsultas não sabendo quando quebrar linha) não se resolvem com pressionamentos manuais de Tab.
O valor central de um formatador SQL não é “fazer o SELECT ficar bonito” — é fazer as consultas serem legíveis por humanos durante revisão de código, análise post-mortem e inspeção de logs de consultas lentas. Isso é infraestrutura, não embelezamento. Este artigo cobre 8 foot-guns reais no formato “sintoma + porquê + como corrigir”, depois apresenta o Piick SQL Formatter — 5 dialetos, 3 modos de capitalização, 4 modos de indentação, vírgula no início/fim, destaque de sintaxe, salto com clique para posição de erro, 5 estatísticas, processamento 100% local, tudo em 1 minuto.
Resumo em 30 Segundos
-
Formatador SQL != embelezador: o primeiro é infraestrutura de legibilidade para auditorias de consultas / revisão de código / análise de logs de consultas lentas; o segundo é apenas “fazer o código ficar arrumado”
-
O dialeto decide tudo: o mesmo
SELECT * FROM "my column"é uma string no MySQL, um identificador entre aspas no PostgreSQL e um erro de sintaxe no T-SQL. Um formatador sem consciência de dialeto inevitavelmente reescreverá e quebrará coisas -
8 foot-guns comuns: incompatibilidade de dialeto, capitalização mista de palavras-chave, ponto e vírgula dentro de strings disparando splits falsos, formatador ingênuo engolindo comentários, aspas de identificador reescritas automaticamente, formatação não recursiva de WITH CTE, todas as subconsultas inline em vez de tabelas derivadas com sua própria linha, SQL minificado perdendo toda estrutura para depuração
-
Direção da correção: use sempre um formatador com opções de dialeto, nunca reescreva aspas automaticamente, sempre trate comentários / CTEs / tabelas derivadas como cidadãos de primeira classe
-
Use o Piick SQL Formatter online para formatar / minificar / embelezar — 5 dialetos, destaque de sintaxe, salto com clique para posição de erro, processamento 100% local, seguro para colar DDL de produção
8 Foot-Guns Comuns
Foot-Gun 1: Incompatibilidade de Dialeto (Backtick do MySQL Roda no PG e Quebra)
Sintoma: Uma consulta PostgreSQL, passada por um formatador estilo MySQL, sai com todos os "my column" reescritos como `my column`. Cole de volta no psql e você obtém ERROR: column "my column" does not exist (porque PG usa aspas duplas para identificadores, e backticks não são sintaxe legal).
Porquê: O caractere de aspa de identificador de cada dialeto é diferente — MySQL usa ` backtick, PostgreSQL / SQLite / Standard SQL usam " aspas duplas, T-SQL usa [ ] colchetes ou aspas duplas. Um formatador ingênuo vê uma string e a trata como string, sem considerar o contexto do dialeto, então reescreve um identificador PG sob as regras do MySQL em um backtick.
Solução: O formatador DEVE ter um seletor de dialeto, e o dialeto decide 2 coisas — (a) o conjunto de reconhecimento de palavras-chave (~120 palavras reservadas, diferente por dialeto), e (b) o caractere de aspa de identificador. O Piick SQL Formatter alterna entre 5 dialetos; cole SQL PG e selecione PostgreSQL, e o formatador não tocará nas suas aspas.
Cenário real: Ao migrar PG → MySQL, uma operação reversa ingênua reescreve o "my column" do PG para `my column` do MySQL, mas a coluna JSONB do PG se torna JSON do MySQL, o SERIAL do PG se torna AUTO_INCREMENT do MySQL — isso não é algo que o formatador pode corrigir (você tem que reescrever o schema manualmente). Mas “erros de sintaxe causados pelo próprio formatador ao reescrever aspas” devem ser tolerância zero.
Foot-Gun 2: Capitalização Mista de Palavras-Chave (Grep Não Encontra Cláusulas)
Sintoma: Durante revisão de código, git blame mostra um SELECT como Select * From users Where id = 1. Você quer grepar todas as cláusulas WHERE no código com a regex \bWHERE\b (case-sensitive) — zero correspondências. Mude para -i, e você encontra 70% where em minúscula e 30% WHERE em maiúscula, porque 5 templates de formatador usam UPPER, 3 usam lower, e o resto ignora.
Porquê: Quando o formatador não aplica capitalização de palavras-chave, os desenvolvedores escrevem o que sua config do editor (camelCase, snake_case) sugere, e o código acaba com 4 estilos de capitalização misturados — Select / SELECT / select / sElEcT (sim, as pessoas realmente escrevem isso). Palavras-chave SQL são case-insensitive, então a semântica funciona, mas revisão de código, grep e ferramentas de análise AST quebram.
Solução: O formatador deveria oferecer uma opção de capitalização de palavras-chave (UPPER / lower / Preserve), a equipe deveria travar um estilo em um arquivo de config estilo ESLint, e CI deveria rodar o formatador para aplicá-lo automaticamente. O Piick SQL Formatter alterna entre 3 modos de capitalização — escolha UPPER e todas as palavras-chave se tornam SELECT FROM WHERE; escolha Preserve e a capitalização original é mantida (bom para projetos que já têm um estilo estabelecido).
Cenário real: Ao aceitar um PR em um projeto open-source, um novo contribuidor mistura capitalização; o revisor comenta “por favor rode o formatador antes de enviar”; o contribuidor instala o prettier-plugin-sql recomendado do projeto e roda, o que reformata 200 linhas não relacionadas, e o revisor tem que revisar de novo. A unificação de capitalização deveria acontecer uma vez antes do commit, não repetidamente durante a revisão.
Foot-Gun 3: Ponto e Vírgula Dentro de Strings Dispara Splits Falsos (SQL Inteiro se Despedaça)
Sintoma: Um INSERT VALUES contém dados sujos com ; dentro de uma string de entrada do usuário (por exemplo notes = 'Error: connection refused; retry';). O formatador ingênuo divide por ;, gerando 2 pseudo-sentenças; cole de volta para executar, a segunda “sentença” são caracteres lixo e o banco de dados lança um erro de sintaxe.
Porquê: O formatador ingênuo usa src.split(';') para dividir SQL multi-sentença, ignorando completamente o estado de aspas — ; dentro de uma string é textualmente indistinguível de um terminador de sentença. A abordagem correta é o tokenizer primeiro reconhecer aspas / comentários / aninhamento, depois dividir por ;, cortando apenas em estado não-string / não-comentário.
Solução: O primeiro gate de qualquer ferramenta de processamento SQL é o tokenizer. Um split(';') ingênuo funciona em um demo, mas quebra no momento em que dados de produção (com entradas de usuário contendo ;) chegam. O tokenizer do Piick SQL Formatter é a nível de caractere, reconhecendo '...', "..." (identificador PG), `...` (identificador MySQL), comentários de bloco aninhados /* ... */, comentários de linha -- ..., e comentários de linha MySQL # ... — dentro de todos esses contextos o ; nunca é um terminador de sentença.
Cenário real: Um script de migração de dados exporta INSERTs a partir de CSV; o CSV contém ; em entradas de usuário como dado de negócio legítimo (por exemplo, campos de texto de sentenças SQL, campos de descrição CSV). O script ingênuo quebra imediatamente; a abordagem correta é usar uma ferramenta com tokenizer para dividir, ou usar o protocolo COPY (não monte INSERTs).
Foot-Gun 4: Comentários Engolidos Silenciosamente por Formatador Ingênuo (Condições WHERE Desaparecem)
Sintoma: SELECT * FROM users WHERE active = 1 -- apenas usuários ativos — depois que o formatador ingênuo roda, o comentário desaparece, deixando SELECT * FROM users WHERE active = 1, que parece OK. Mas você revisa o git diff e vê que o comentário foi removido silenciosamente — o comentário era uma explicação de negócio para “por que esta cláusula WHERE está escrita assim”, e uma vez removido, 6 meses depois você não tem ideia de por que active=1.
Porquê: Muitos formatadores fundem os dois passos “formatar = deletar comentários + re-distribuir tokens”. Tokens de comentário não afetam a semântica, então são descartados como lixo. Mas comentários são evidência chave da evolução do schema (“por que este campo está hardcoded em 1 em vez de config”, “por que esta tabela deprecated é joinada”), e deletá-los é deletar o histórico do projeto.
Solução: O formatador deve tratar tokens de comentário como cidadãos de primeira classe, preservando posição e conteúdo; apenas o modo minify pode deletá-los (porque minify é para execução em produção, não para leitura humana). O Piick SQL Formatter preserva comentários de linha -- e comentários de bloco /* */ (incluindo aninhados) em modo formato, e apenas deleta comentários em modo “Minify”.
Cenário real: Durante análise de logs de consultas lentas, você vê SELECT * FROM orders WHERE created_at < '2020-01-01' -- consulta temporária pré-arquivamento, deletar após limpeza; depois que o formatador roda uma vez, o comentário desaparece; 6 meses depois você olha este SQL e não sabe “por que created_at está hardcoded em 2020-01-01 — bug ou consulta temporária?” — você tem que perguntar a um colega. Comentários são a máquina do tempo do projeto; deletá-los é deletar o histórico do projeto.
Foot-Gun 5: Aspas de Identificador Reescritas Automaticamente (Portabilidade Cross-Dialeto Quebra)
Sintoma: O SELECT "userId" FROM "users" do PG se torna SELECT \userId` FROM `users“ (backticks MySQL) depois que o formatador ingênuo roda. Cole de volta no PG e você obtém um erro de sintaxe — PG não reconhece backticks como aspas de identificador.
Porquê: O formatador vê uma aspa dupla e a reescreve sob as “regras de aspa de identificador” do seu dialeto sem considerar que tipo de aspa o usuário digitou originalmente. Se o usuário tinha aspas duplas PG / Standard / SQLite, reescrever para backticks é um erro de sintaxe. Se o usuário tinha backticks MySQL, reescrever para aspas duplas também está errado no MySQL (aspas duplas são strings no MySQL, não identificadores, a menos que o modo SQL ANSI_QUOTES esteja ativo).
Solução: O formatador deveria por padrão preservar os caracteres de aspa de entrada e nunca reescrevê-los ativamente. Se o usuário genuinamente quer reescrever o dialeto (por exemplo, PG → MySQL), esse é o trabalho de outra ferramenta — uma ferramenta de migração de schema (Prisma / SQLAlchemy / Flyway), não o formatador. O Piick SQL Formatter preserva estritamente os caracteres de aspa de entrada — as aspas que você cola são as aspas na saída, nunca reescritas.
Cenário real: Uma equipe de ciência de dados exporta uma consulta do PG para uma ferramenta de BI, e a ferramenta de BI usa um motor compatível com MySQL. O cientista de dados manualmente muda SELECT "userId" para SELECT userId (tira as aspas, já que minúscula não precisa delas). Isso é julgamento humano, não trabalho do formatador. O formatador quebrar SQL já correto é o bug mais básico.
Foot-Gun 6: Formatação Não Recursiva de WITH (CTE) (Múltiplos CTEs se Acumulam em Uma Linha)
Sintoma: WITH active_users AS (SELECT id FROM users WHERE active=1), recent_orders AS (SELECT user_id FROM orders WHERE created_at > NOW() - INTERVAL '7 days') SELECT COUNT(*) FROM active_users a JOIN recent_orders r ON a.id = r.user_id — depois do formatador ingênuo, todos os nomes de CTE ficam na primeira linha após WITH, os bodies de CTE não são indentados, e lê igual à entrada não formatada.
Porquê: WITH (CTE) é o mecanismo de nomeação de subconsultas introduzido no padrão SQL. Um WITH pode ter múltiplos nomes de CTE (separados por vírgula), cada um seguido por uma definição (SELECT ...). Um formatador ingênuo distribui “WITH … SELECT” como uma linha e nem considera que CTE é uma lista.
Solução: O formatador deve reconhecer a lista de CTE, dar a cada nome de CTE sua própria linha, indentar o body 1 nível (e o body do SELECT mais 1 nível). Quando múltiplos CTEs aninham (body de um CTE usa WITH de novo), recurse para cada camada. O Piick SQL Formatter formata WITH recursivamente — cada nome de CTE em sua própria linha + body indentado, CTEs aninhados recursos automaticamente.
Cenário real: Uma consulta de analytics da equipe de dados tipicamente encadeia 5-10 CTEs em um pipeline. O formatador ingênuo achata em 3 linhas; o revisor não consegue ler o que cada passo faz. Com formatação CTE recursiva, cada CTE é como uma mini-função independente, melhorando a legibilidade 10x.
Foot-Gun 7: Todas as Subconsultas Inline (Tabelas Derivadas Perdem sua Estrutura)
Sintoma: SELECT u.name, o.total FROM users u JOIN (SELECT user_id, SUM(amount) AS total FROM orders GROUP BY user_id) o ON u.id = o.user_id — o formatador ingênuo põe (SELECT user_id, ... GROUP BY user_id) inline na linha do JOIN, e o painel direito não consegue mostrar uma única linha de 80 caracteres.
Porquê: Subconsultas têm duas semânticas — subconsulta escalar (como parte de uma expressão, por exemplo, WHERE id IN (SELECT ...)) deveria estar inline porque é em si um valor; tabela derivada (na cláusula FROM, FROM (SELECT ...) AS t) deveria estar em sua própria linha porque é uma tabela, e apenas uma linha independente pode mostrar sua estrutura claramente. O formatador ingênuo não distingue e põe tudo inline.
Solução: O formatador deve distinguir subconsulta escalar vs tabela derivada — tabelas derivadas que aparecem na cláusula FROM vão em sua própria linha + indentadas; subconsultas escalares ficam inline. O Piick SQL Formatter segue esta regra — tabelas derivadas automaticamente recebem sua própria linha, escalares ficam inline.
Cenário real: Em uma consulta BI complexa, a cláusula FROM tem 3-4 tabelas derivadas (cada uma uma versão materializada de um CTE); depois de colocar inline, todo o SQL se acumula além de 80 caracteres e você tem que rolar manualmente para ver o resto. Depois da formatação apropriada, cada tabela derivada parece uma mini-tabela, e a legibilidade salta instantaneamente.
Foot-Gun 8: SQL Minificado Perde Legibilidade (Depuração Não Pode Ver Estrutura)
Sintoma: O SQL de produção é gerado por ORM e roda bem após minificação. Mas quando você o puxa do log de consultas lentas, obtém um SQL de linha única de 5KB e não consegue grepar WHERE porque o SQL minificado não tem quebras de linha e lê como 5000 caracteres em uma linha ao olho humano.
Porquê: O propósito da minificação é reduzir bytes de transmissão de rede + deixar o parser do banco de dados parsear mais rápido (embora esse benefício seja insignificante em DBs modernos), não para leitura humana. Desenvolvedores usam SQL minificado em produção e isso está OK, mas para depurar você precisa ver a versão pretty-printed para localizar problemas.
Solução: Implantações de produção usam SQL minificado (economiza transmissão); depuração usa SQL pretty-printed (legibilidade). Isso significa você precisa de 2 versões — ORM gera minificado, a ferramenta formatadora gera pretty-printed para depuração. O sistema de logs também deveria formatar consultas lentas antes de gravar, não gravar o minificado cru. O Piick SQL Formatter suporta modo Minify + 5 estatísticas (sentença / palavra-chave / identificador / string / byte). Cole o SQL minificado de produção para pretty-print instantâneo + ver contagens de sentenças e palavras-chave.
Cenário real: Um DBA investiga uma consulta lenta; o log dá um SQL minificado gerado por ORM; o DBA não consegue ver qual JOIN é N+1. Jogue este SQL no Piick SQL Formatter, selecione Standard SQL + indentação de 2 espaços + vírgula no início, veja a estrutura em 1 segundo, e localize LEFT JOIN order_items oi ON o.id = oi.order_id WHERE oi.id IS NULL como a fonte do N+1.
Decisões de Seleção de Ferramenta
Opção A: Plugin do Editor (SQLTools / DataGrip / DBeaver)
Melhor para: Pessoas que escrevem SQL todo dia e já usam um IDE.
Pros: Formatação em tempo real, sem sair do editor, integração automática com autocomplete de schema. Contras: Apenas SQL local, não consegue sincronizar entre dialetos (seu IDE tem formatador MySQL, produção é PG, reescrita de aspas quebra), sem processamento em lote (auto-formato em CI requer setup separado).
Opção B: Pacote npm sql-formatter
Melhor para: Auto-formatação em CI / pipeline de build, projetos com ambiente Node.js.
Pros: Pode integrar em CI, CI falha diretamente com erro, versão fixada para garantir consistência da equipe. Contras: ~200KB de dependência + um monte de deps transitivas, atualizações de versão ocasionalmente quebram SQL antigo, requer ambiente Node (projetos puramente frontend não podem usar), sem destaque de sintaxe + salto com clique para posição de erro (saída de texto puro).
Opção C: Piick SQL Formatter
Melhor para: Processamento cross-dialeto (o mesmo SQL alternando entre 5 dialetos para ver qual está correto), projetos que não querem pacotes npm (puramente frontend), dados sensíveis (DDL de produção, consultas com PII) que não deveriam passar por nenhum servidor de terceiros, DBAs / revisão de código em equipe necessitando visão estrutural rápida.
Pros: Zero dependência (processamento puramente frontend token + AST), 5 dialetos (Standard / MySQL / PostgreSQL / SQLite / T-SQL), 3 modos de capitalização de palavras-chave, 4 modos de indentação, vírgula no início/fim, destaque de sintaxe, salto com clique para posição de erro, 5 estatísticas, processamento 100% local. Contras: Não pode integrar em CI (use Opção B para isso), não pode auto-salvar (ferramenta puramente frontend, tem que copiar manualmente).
Árvore de decisão:
-
Já escreve SQL a nível de projeto → Opção A (plugin IDE)
-
Integração CI + ambiente Node → Opção B (pacote npm)
-
Depuração cross-dialeto + dados sensíveis + não instalar nada → Opção C (Piick)
5 Cenários Reais
Cenário 1: Migração de Dados Cross-Dialeto (PG → MySQL)
O SELECT "userId", COUNT(*) FROM "users" WHERE "createdAt" > NOW() - INTERVAL '7 days' GROUP BY "userId" do PG — você quer executá-lo no MySQL (ambiente de teste não tem PG, use MySQL temporariamente). Passos:
-
Use o Piick SQL Formatter e selecione PostgreSQL; primeiro formate a versão PG (preservando aspas duplas + palavras-chave PG)
-
Ajuste manualmente itens relacionados a schema:
"users" -> users(tire as aspas, já que minúscula não precisa delas),INTERVAL '7 days'se tornaDATE_SUB(NOW(), INTERVAL 7 DAY) -
Volte para Piick e selecione MySQL; reformate o SQL modificado (para que o reconhecimento de palavras-chave do MySQL se alinhe)
-
Cole no MySQL para executar
Não faça: Usar operações reversas ingênuas (o formatador reescreve automaticamente aspas duplas PG para backticks MySQL), o SQL tem erros de sintaxe + erros de nome de campo empilhados, tempo de depuração dobra.
Cenário 2: Revisão de Código Não Consegue Ler a Ordem de JOIN
PR da equipe tem SELECT * FROM a LEFT JOIN b ON a.id = b.a_id INNER JOIN c ON b.c_id = c.id WHERE ..., revisor olha por 5 minutos sem entender a semântica da ordem de JOIN. Use o Piick SQL Formatter com Standard SQL + indentação de 4 espaços; cole e veja a estrutura em 1 segundo:
SELECT
FROM
a
LEFT JOIN b
ON a.id = b.a_id
INNER JOIN c
ON b.c_id = c.id
WHERE
…
Revisor imediatamente vê “primeiro LEFT JOIN b (pode expandir linhas), depois INNER JOIN c (filtra linhas onde b não combinou)”, problema de performance fica claro de relance.
Cenário 3: SQL Minificado do Log de Consultas Lentas Restaurado
DBA obtém um SQL de linha única de 5KB gerado por ORM, não consegue ver o N+1. Cole no Piick SQL Formatter, mude de Minify para indentação de 4 espaços; veja a estrutura em 1 segundo, localize LEFT JOIN order_items oi ON o.id = oi.order_id WHERE oi.id IS NULL como a fonte do N+1. Combinado com o Regex Tester do Piick para grepar palavras-chave na saída EXPLAIN ANALYZE, localize a subconsulta lenta específica.
Cenário 4: Pipeline CTE Aninhado (Consulta Analytics da Equipe de Dados)
A consulta da equipe de dados encadeia 8 CTEs em um pipeline; o editor ingênuo achata em one-liners de 80 caracteres, e o revisor não consegue dizer o que cada passo faz. Use o Piick SQL Formatter para formatação WITH recursiva, cada CTE se torna uma mini-função independente:
WITH
step1_active_users AS (
SELECT
id
FROM
users
WHERE
active = 1
),
step2_recent_orders AS (
…
),
step3_joined AS (
SELECT
…
FROM
step1_active_users a
JOIN step2_recent_orders r
ON a.id = r.user_id
)
SELECT
…
FROM
step3_joined
Revisor consegue ler o pipeline como código.
Cenário 5: DDL de Produção Nunca Sai do Navegador
Equipe de dados precisa sincronizar o CREATE TABLE users (...) do PG para staging; o DDL contém campos sensíveis (schema de campo de ID de usuário criptografado). Não pode usar um formatador online (medo do SQL ser enviado); use o Piick SQL Formatter para processamento puramente frontend, 100% local, cole, copie o resultado, feche a página, nem rastro do SQL. Combinado com o URL Encoder/Decoder do Piick para lidar com nomes de campos URL-encoded em DDL, e o JSON Formatter para defaults JSON / JSONB em DDL.
Práticas Recomendadas
-
Sempre use um formatador com opções de dialeto; pelo menos cubra Standard / MySQL / PG / SQLite / T-SQL entre os 5 dialetos. Um formatador ingênuo inevitavelmente quebrará em projetos cross-dialeto
-
Sempre preserve os caracteres de aspa de entrada (aspas duplas / backtick / colchete), nunca reescreva ativamente. Reescrever é trabalho da ferramenta de migração de schema, não do formatador
-
Trate comentários como cidadãos de primeira classe; o formatador não deleta comentários — comentários são a máquina do tempo do projeto, a única evidência 6 meses depois explicando “por que foi escrito assim”
-
Processamento recursivo para WITH (CTE); cada CTE ganha sua própria linha, body indentado, CTEs aninhados recursam de novo
-
Distinga subconsulta escalar vs tabela derivada: escalares inline (são valores), tabelas derivadas em sua própria linha (são tabelas)
-
Produção usa minificado, depuração usa pretty-printed; 2 versões cada uma serve ao seu próprio propósito
-
Integração CI: SQL a nível de projeto usa o pacote npm
sql-formatter(ou equivalente) para formatação unificada, para evitar mudanças de formato repetidas durante revisão -
DDL sensível usa uma ferramenta puramente frontend como Piick: 100% local, cole → copie → feche página, sem rastro
-
Estatísticas são essenciais: depois de colar, olhe as 5 métricas (sentenças / palavras-chave / identificadores / strings / bytes) para uma verificação rápida da estrutura SQL (por exemplo, contagem de identificadores dispara de repente, significando que FROM JOIN adicionou várias tabelas, possivelmente ORM gerou errado)
Formatação SQL é infraestrutura de legibilidade para auditorias de consultas e revisão de código, não decoração. Salve o Piick SQL Formatter nos favoritos — para depuração cross-dialeto / restauração de logs de consultas lentas / investigação de DDL de produção, abra e você termina em 1 minuto. Combinado com o Piick JSON Formatter para colunas JSON / JSONB, o Piick URL Encoder/Decoder para campos URL em cláusulas WHERE, o Piick Regex Tester para grepar palavras-chave na saída EXPLAIN, e o Piick Cron Generator para expressões cron agendando SQL — essas 5 ferramentas juntas cobrem os cenários completos upstream/downstream de SQL.