DISTINCT remove linhas duplicadas
Por padrão, o SELECT devolve todas as linhas que batem com a consulta, inclusive as repetidas. O DISTINCT avisa o SQLite para agrupar as linhas que são iguais nas colunas selecionadas, fazendo com que cada combinação única apareça uma vez só.
Cinco linhas entraram, três saíram. O SQLite olhou para a coluna customer, descartou as repetidas e devolveu uma linha por valor único. A ordem não é garantida — se isso te importa, use ORDER BY.
DISTINCT atua sobre toda a lista do SELECT
Aqui é onde muita gente tropeça. O DISTINCT não escolhe uma coluna para remover duplicados; ele elimina linhas inteiras com base em todas as colunas que você selecionou.
Cada par único (customer, country) aparece uma vez só. Se o mesmo cliente aparecesse com dois países diferentes, você veria as duas linhas — para o SQLite, elas não são duplicadas.
Não existe uma sintaxe DISTINCT(customer) que ignore as outras colunas. Os parênteses até parecem indicar isso, mas SELECT DISTINCT(customer), country é interpretado igualzinho a SELECT DISTINCT customer, country — os parênteses servem apenas para agrupar uma expressão. Se você quer mesmo uma linha por cliente com algum país escolhido, aí o caminho é usar GROUP BY com uma função de agregação.
COUNT(DISTINCT col)
Uma necessidade super comum: quantos valores únicos existem em uma coluna? COUNT(*) conta linhas, COUNT(col) conta valores não-NULL e COUNT(DISTINCT col) conta valores únicos não-NULL.
Cinco pedidos, três clientes únicos, três países únicos. O COUNT(DISTINCT ...) é a forma agregada mais útil do DISTINCT — você vai usar sempre que precisar contar "quantas coisas diferentes apareceram".
Vale lembrar que o SQLite só aceita uma única coluna dentro do COUNT(DISTINCT ...). Para contar combinações únicas de várias colunas, envolva tudo em uma subquery: SELECT COUNT(*) FROM (SELECT DISTINCT a, b FROM t).
Como o DISTINCT trata NULL no SQLite
O NULL tem uma fama meio esquisita no SQL, já que NULL = NULL resulta em NULL, e não em TRUE. Mas o DISTINCT abre uma exceção especial: na hora de remover duplicados, todos os NULLs são considerados iguais entre si.
Voltam três linhas: 'ada@example.com', 'dan@example.com' e um único NULL. Os três e-mails NULL foram fundidos em um só. A mesma regra vale para o GROUP BY e para operações de conjunto como UNION — vale a pena lembrar disso quando você estiver investigando "por que essa linha NULL aparece só uma vez em vez de três?"
DISTINCT é executado antes de ORDER BY e LIMIT
As cláusulas de um SELECT seguem uma ordem lógica: FROM → WHERE → GROUP BY → HAVING → SELECT/DISTINCT → ORDER BY → LIMIT. Ou seja, o DISTINCT elimina os duplicados primeiro, depois o ORDER BY ordena o que sobrou e, por fim, o LIMIT corta o resultado.
WHERE mantém quatro linhas, o DISTINCT elimina as duplicatas do Boris, o ORDER BY ordena em ordem alfabética e o LIMIT devolve as duas primeiras. Vale a pena seguir esse passo a passo uma vez — quando o resultado vem em uma ordem inesperada, quase sempre é porque a gente esqueceu em que momento cada etapa acontece.
DISTINCT vs GROUP BY no SQLite
Quando o objetivo é só remover duplicados, essas duas consultas retornam exatamente as mesmas linhas:
Mesmo resultado. A diferença está no que você pode fazer depois:
DISTINCTserve só pra isso: "me devolva linhas únicas", e ponto.GROUP BYserve pra "agrupar linhas e calcular algo por grupo" —COUNT(*),SUM(amount),MAX(created_at)e por aí vai.
Se você se pegar usando DISTINCT e logo perceber que também quer um total por cliente, esse é o sinal de que é hora de mudar pra GROUP BY:
Uma linha por cliente, com os agregados que você queria. O DISTINCT não daria conta disso — ele não tem como expressar "uma linha por grupo mais uma soma".
Alguns pontos de atenção
- Performance. Em geral, o
DISTINCTforça o SQLite a ordenar ou fazer hash das linhas para localizar duplicatas. Em resultados grandes, um índice na(s) coluna(s) que está sendo deduplicada ajuda bastante. Se você está fazendoSELECT DISTINCTem todas as colunas de uma tabela larga, vale a pena se perguntar se você realmente precisa de todas elas. DISTINCT *é raro. É válido —SELECT DISTINCT * FROM tremove duplicados considerando a linha inteira — mas se sua tabela tem chave primária, toda linha já é única, então isso não serve para nada na prática.- Não confunda com
UNIQUE.UNIQUEé uma restrição de tabela que impede a inserção de valores duplicados desde o começo. Já oDISTINCTé um filtro aplicado na hora da consulta, que esconde duplicados no resultado. Ferramentas diferentes, com propósitos diferentes.
A seguir: expressões CASE
Depois que você consegue moldar as linhas do resultado com SELECT, WHERE, ORDER BY e DISTINCT, o próximo passo é trazer lógica condicional para dentro da consulta. As expressões CASE permitem retornar valores diferentes conforme as condições — é o equivalente em SQL a uma escada de if/else, e é o assunto da próxima página.
Perguntas frequentes
Como funciona o SELECT DISTINCT no SQLite?
O SELECT DISTINCT elimina linhas duplicadas do resultado. O SQLite compara todas as colunas que estão na lista do SELECT e mantém apenas uma linha para cada combinação única. Ele é aplicado depois do WHERE e dos JOIN, mas antes do ORDER BY e do LIMIT.
Dá para usar DISTINCT em várias colunas no SQLite?
Dá sim — na verdade, o DISTINCT sempre considera a lista inteira de colunas do SELECT, nunca uma só. Por exemplo, SELECT DISTINCT city, country FROM users retorna cada par (city, country) único. Não existe uma sintaxe DISTINCT(city) que ignore as outras colunas; quando você precisa disso, o caminho é usar GROUP BY com uma função de agregação.
Como o DISTINCT trata valores NULL no SQLite?
Para fins de deduplicação, o DISTINCT considera que NULL é igual a outro NULL — ou seja, várias linhas com NULL viram uma só. Isso é diferente do que acontece no WHERE, onde NULL = NULL dá resultado desconhecido. É uma regra especial que vale só para DISTINCT, GROUP BY e UNION.
Qual a diferença entre DISTINCT e GROUP BY no SQLite?
Se o objetivo é só remover duplicatas, SELECT DISTINCT col e SELECT col FROM t GROUP BY col entregam exatamente o mesmo resultado. A diferença está na intenção: use DISTINCT quando você só quer linhas únicas, e GROUP BY quando também precisa calcular agregações por grupo, como COUNT(*) ou SUM(amount).