Vírgulas à esquerda ou à direita em SQL
A vírgula deve ficar no fim da linha ou no começo da próxima? Este guia compara os dois estilos no que realmente importa: diffs, comentar linhas, encontrar uma vírgula faltando e legibilidade, e termina com um checklist para ajudar o seu time a decidir.
Poucas questões de formatação geram tantas discussões quanto a posição da vírgula. Os dois estilos produzem exatamente a mesma consulta para o banco de dados; a diferença está inteiramente em como as pessoas leem, editam e revisam o código. Isso faz dela uma decisão do time, não uma questão de correção, e a melhor resposta é aquela que o seu time aplica de forma consistente.
Os dois estilos
Vírgulas à direita colocam a vírgula no fim de cada linha, logo depois do item que ela acompanha, do mesmo jeito que as vírgulas são usadas num texto comum e na maioria das linguagens de programação. Vírgulas à esquerda (às vezes chamadas de comma-first) colocam a vírgula no começo da linha seguinte, imediatamente antes do item que ela introduz. Veja a mesma consulta formatada dos dois jeitos, com commas=after e commas=before:
select o.order_id, o.created_at, c.customer_name, c.email, o.total_amount from orders o join customers c on c.customer_id = o.customer_id where o.status = 'open' order by o.created_at, o.order_id;SELECT o.order_id,
o.created_at,
c.customer_name,
c.email,
o.total_amount
FROM orders o
JOIN customers c
ON c.customer_id = o.customer_id
WHERE o.status = 'open'
ORDER BY o.created_at,
o.order_id;SELECT o.order_id
,o.created_at
,c.customer_name
,c.email
,o.total_amount
FROM orders o
JOIN customers c
ON c.customer_id = o.customer_id
WHERE o.status = 'open'
ORDER BY o.created_at
,o.order_id;Só mudam a lista do select e a lista do ORDER BY. No estilo à esquerda, o formatador escreve a vírgula imediatamente antes do item, como ,o.created_at, sem espaço depois dela. O restante do layout é idêntico. Você pode alternar entre os dois estilos a qualquer momento com a opção Vírgulas.
De onde vem cada estilo
As vírgulas à direita são o padrão em quase todo lugar, porque seguem os hábitos normais de escrita. A maior parte do SQL que você encontra em documentação, livros, consultas geradas por ORMs e ferramentas de banco de dados usa esse estilo, e a maioria das pessoas o escreve sem nunca pensar nisso.
As vírgulas à esquerda são uma escolha deliberada. Elas costumam aparecer em times que escrevem e mantêm muito SQL à mão, como em relatórios, data warehouse e análise de dados, em que as listas do select são longas e colunas são adicionadas, removidas e comentadas o tempo todo. A mesma ideia aparece em algumas outras linguagens, em listas que mudam com frequência. A motivação é sempre prática: fazer com que as edições mais comuns mexam no menor número possível de linhas e manter os delimitadores da lista numa coluna previsível.
Diffs: adicionando e removendo o último item
Este é o argumento mais citado a favor das vírgulas à esquerda, e ele é verdadeiro. Suponha que você adicione o.currency_code no fim de uma lista do select. Com vírgulas à direita, a linha que antes era a última precisa ganhar uma vírgula, então o diff mostra essa linha como alterada:
--- a/reports/open_orders.sql
+++ b/reports/open_orders.sql
@@ -1,4 +1,5 @@
SELECT o.order_id,
o.created_at,
- o.total_amount
+ o.total_amount,
+ o.currency_code
FROM orders oCom vírgulas à esquerda, o novo item traz a sua própria vírgula, e as linhas existentes não são tocadas:
--- a/reports/open_orders.sql
+++ b/reports/open_orders.sql
@@ -1,4 +1,5 @@
SELECT o.order_id
,o.created_at
,o.total_amount
+ ,o.currency_code
FROM orders oA versão com vírgulas à direita mostra duas linhas alteradas para uma mudança de uma única coluna, e o git blame passa a atribuir o.total_amount à pessoa que adicionou currency_code. Remover o último item é o espelho disso: no estilo à direita, também é preciso editar a nova última linha para tirar a sua vírgula. O quadro completo, porém, é mais equilibrado:
| Mudança na lista | Vírgulas à direita | Vírgulas à esquerda |
|---|---|---|
| Adicionar um item no fim | 1 linha adicionada, 1 linha alterada | 1 linha adicionada |
| Remover o último item | 1 linha removida, 1 linha alterada | 1 linha removida |
| Inserir ou remover um item no meio | 1 linha adicionada ou removida | 1 linha adicionada ou removida |
| Inserir ou remover o primeiro item | primeira linha alterada, 1 linha adicionada ou removida | primeira linha alterada, 1 linha adicionada ou removida |
As vírgulas à esquerda transferem o problema do fim da lista para o começo. Como o formatador mantém o primeiro item do select na linha do SELECT, alterar o primeiro item mexe nessa linha em qualquer um dos estilos. Na prática, colunas são adicionadas no fim com muito mais frequência do que no começo, e é por isso que o argumento dos diffs favorece as vírgulas à esquerda no dia a dia. Se isso importa ou não depende de quantas vezes as suas listas mudam e de quão atentamente o seu time lê os diffs.
Comentando linhas
Ao explorar dados ou depurar um relatório, é comum desativar uma coluna comentando a sua linha. Cada estilo tem uma posição em que isso quebra a consulta. Com vírgulas à direita, é o último item, porque a linha anterior fica com uma vírgula sem nada depois dela:
-- Trailing commas: commenting out the LAST column breaks the query
SELECT o.order_id,
o.created_at,
o.total_amount,
-- o.currency_code
FROM orders o;
-- Commenting out the FIRST column is safe
SELECT
-- o.order_id,
o.created_at,
o.total_amount
FROM orders o;Com vírgulas à esquerda, a última linha é segura, e o problema passa a ser a primeira, porque o segundo item agora começa com uma vírgula:
-- Leading commas: commenting out the LAST column is safe
SELECT o.order_id
,o.created_at
,o.total_amount
-- ,o.currency_code
FROM orders o;
-- Commenting out the FIRST column breaks the query
SELECT
-- o.order_id
,o.created_at
,o.total_amount
FROM orders o;De novo, a vantagem das vírgulas à esquerda é uma questão de frequência: em trabalho exploratório, as pessoas costumam ligar e desligar colunas perto do fim da lista. Se o seu fluxo de trabalho envolve comentar muitas linhas, esse é um motivo prático para preferi-las. Se não envolve, é um ponto menor.
Procurando uma vírgula faltando
Uma vírgula faltando é o erro de vírgula que mais machuca, porque muitas vezes não causa erro nenhum. Na maioria dos bancos de dados, o AS é opcional antes de um alias de coluna, então dois nomes de coluna separados apenas por espaço são lidos como uma coluna e o seu alias:
-- Trailing commas: the missing comma hides at the end of a line
SELECT order_id,
created_at
total_amount,
status
FROM orders;
-- Leading commas: the gap is visible in the left margin
SELECT order_id
,created_at
total_amount
,status
FROM orders;As duas consultas rodam. As duas retornam três colunas em vez de quatro, e a coluna chamada total_amount na verdade contém created_at. No estilo à direita, a vírgula faltando fica no fim de uma linha, onde o olho raramente olha, e linhas de tamanhos diferentes deixam a falha mais difícil de ver. No estilo à esquerda, todo item depois do primeiro começa com uma vírgula na mesma coluna, então a linha sem vírgula salta aos olhos.
Dois hábitos protegem você seja qual for o estilo escolhido: escreva AS antes de todo alias de coluna, para que um alias sem AS pareça errado, e deixe um formatador organizar a lista com um item por linha. Um formatador não vai adicionar uma vírgula que falta, mas, com cada item na sua própria linha, uma linha que contém dois nomes fica fácil de identificar.
Listas do SELECT e listas do IN
A posição da vírgula também afeta listas de valores, não apenas listas de colunas. O formatador aplica o estilo escolhido às listas que ele quebra em várias linhas: a lista do select, os valores dentro de IN (...) e as listas do GROUP BY e do ORDER BY:
select order_id, status, total_amount from orders where status in ('open', 'pending', 'on_hold') and region_id in (10, 20, 30) group by order_id, status, total_amount;SELECT order_id,
status,
total_amount
FROM orders
WHERE status IN (
'open',
'pending',
'on_hold'
)
AND region_id IN (
10,
20,
30
)
GROUP BY order_id,
status,
total_amount;SELECT order_id
,status
,total_amount
FROM orders
WHERE status IN (
'open'
,'pending'
,'on_hold'
)
AND region_id IN (
10
,20
,30
)
GROUP BY order_id
,status
,total_amount;As vírgulas à esquerda ficam naturais numa lista do select longa, em que cada linha é uma coluna com significado. Numa lista curta de valores literais, elas parecem mais pesadas, e algumas pessoas acham ,'pending' mais difícil de ler do que 'pending',. Como uma única configuração vale para todas essas listas, vale a pena formatar algumas das suas consultas reais dos dois jeitos antes de decidir.
A configuração vai além das listas de colunas e de valores. Ela também vale para as consultas nomeadas de uma cláusula WITH, para expressões CASE numa lista do select, para as listas de SET e RETURNING, para as listas de colunas e de VALUES de um INSERT e para as definições de colunas de um CREATE TABLE. Dentro de uma CTE ou de uma subconsulta, as vírgulas se alinham na indentação do próprio bloco:
WITH order_totals AS (
SELECT customer_id
,COUNT(*) AS order_count
,SUM(total_amount) AS revenue
FROM orders
GROUP BY customer_id
)
,segments AS (
SELECT customer_id
,revenue
,CASE WHEN revenue >= 10000 THEN
'key'
WHEN revenue >= 1000 THEN
'regular'
ELSE
'occasional'
END AS segment
FROM order_totals
)
SELECT s.customer_id
,s.segment
,s.revenue
FROM segments s
ORDER BY s.revenue DESCRepare onde fica a vírgula entre as duas CTEs: na frente do segundo nome, como ,segments AS (, em vez de depois do parêntese de fechamento da primeira.
Legibilidade e familiaridade
Os argumentos de legibilidade valem para os dois lados. Quem defende as vírgulas à esquerda gosta da margem esquerda limpa: os itens da lista ficam alinhados, e a coluna das vírgulas funciona como um marcador visual de "esta linha continua a lista". Quem defende as vírgulas à direita lembra que esse é o jeito como todo mundo escreve listas em outras linguagens e em texto comum, então novos membros do time, geradores de código e documentação já usam esse estilo. Nenhum dos lados está errado, e a familiaridade costuma vencer: depois de algumas semanas, a maioria das pessoas acha perfeitamente legível o estilo que usa todos os dias.
O que realmente prejudica a legibilidade é misturar os dois. Um arquivo em que algumas consultas usam vírgulas à esquerda e outras à direita obriga quem lê a parar e se ajustar. É por isso que a decisão deve ser tomada uma única vez, por repositório, e depois garantida pela formatação, e não pela memória.
Um checklist para a decisão do time
Passe por estas perguntas com o seu time e depois registre a resposta junto com as outras convenções de SQL:
- O que o código existente usa? Se a maior parte da base de código já usa um estilo, trocar tem um custo: um commit grande de reformatação e um período de adaptação. Só troque se houver um motivo claro.
- Com que frequência as suas listas mudam? Listas do select longas e editadas com frequência (relatórios, pipelines de dados) se beneficiam mais das vírgulas à esquerda do que consultas de aplicação curtas e estáveis.
- Quanta edição exploratória acontece? Se as pessoas comentam e descomentam colunas o tempo todo, as vírgulas à esquerda evitam erros pequenos, mas frequentes.
- Com que atenção vocês leem diffs e blame? Se as revisões são feitas linha a linha e o histórico importa, os diffs de uma linha das vírgulas à esquerda são um benefício real.
- De onde mais vem o SQL? SQL gerado, trechos copiados de documentação e consultas vindas de ferramentas vão usar, na maioria, vírgulas à direita. Decida se vocês vão reformatá-los quando entrarem no repositório.
- Uma ferramenta consegue aplicar o estilo? Escolha um estilo que o seu formatador suporte, para que ninguém precise aplicá-lo à mão. Os dois estilos estão disponíveis no SQL Format.
- Está documentado? Registre a decisão, junto com as outras opções de formatação, no repositório, onde todos possam encontrá-la.
Perguntas frequentes
A posição da vírgula afeta o desempenho ou o resultado da consulta?
Não. Os espaços em branco e a posição das vírgulas entre os itens são ignorados pelo parser do banco de dados. Os dois estilos produzem exatamente o mesmo plano de execução e os mesmos resultados.
Posso converter SQL existente de um estilo para o outro?
Sim. Cole a consulta no formatador, configure a opção Vírgulas como Depois para vírgulas à direita ou Antes para vírgulas à esquerda, e formate. Faça a conversão num commit separado, para que ela não esconda mudanças de lógica.
O SQL permite uma vírgula depois do último item?
O SQL padrão não permite, e a maioria dos bancos de dados rejeita uma vírgula depois do último item de uma lista do select. É por isso que comentar a última coluna no estilo à direita quebra a consulta.
Para saber mais sobre como manter os diffs de SQL pequenos e as revisões focadas, leia formatação de SQL para revisão de código e controle de versão. O guia de estilo de SQL trata das outras convenções que vale a pena combinar ao mesmo tempo.