SQL SELECT DISTINCT

A dona da Loja Aurora quer saber: "em quais cidades nós temos clientes?". A Ana pede a coluna cidade da tabela de clientes e recebe 30 linhas, com Teresina aparecendo dez vezes. A resposta está ali, mas escondida no meio das repetições. Para isso existe o DISTINCT (em inglês, "distinto", "diferente"): ele tira as linhas repetidas do resultado e deixa cada valor aparecer uma vez só.

Você vai aprender
  • Por que um SELECT comum mostra valores repetidos.
  • A usar SELECT DISTINCT para ver cada valor uma vez só.
  • Como o DISTINCT funciona com várias colunas: ele olha a linha inteira.
  • O que acontece com o NULL num DISTINCT.
  • Outras formas de chegar ao mesmo resultado, e os erros mais comuns.

A ideia: a lista de cidades sem repetir

Imagine as 30 fichas de clientes da loja. Para responder "em quais cidades temos clientes?", você pegaria uma folha em branco, passaria ficha por ficha e anotaria a cidade, só se ela ainda não estiver na folha. No fim, a folha teria cada cidade uma vez.

É exatamente o que o DISTINCT faz com o resultado de um SELECT: monta a resposta normalmente e, antes de mostrar, joga fora as linhas que são iguais a uma que já apareceu.


1. O problema: valores repetidos

Primeiro, a consulta sem DISTINCT:

SELECT cidade FROM clientes;

Vieram 30 linhas, uma por cliente. Isso está certo: o SELECT mostra uma linha do resultado para cada linha da tabela. Como 10 clientes moram em Teresina, Teresina aparece 10 vezes; São Paulo e Fortaleza aparecem 7 vezes cada. Para a pergunta da dona da loja, essas repetições só atrapalham.


2. A solução: SELECT DISTINCT

Basta escrever DISTINCT logo depois do SELECT:

SELECT DISTINCT cidade FROM clientes;
SELECT
"Selecione", como sempre.
DISTINCT
"Distintos": mostre cada linha do resultado uma vez só. Vem colado no SELECT, antes da lista de colunas.
cidade
A coluna que você quer ver.
FROM clientes;
De qual tabela, e o fim do comando.

Agora são 8 linhas: a loja tem clientes em 8 cidades. A tabela clientes continua com os mesmos 30 clientes; o DISTINCT só mudou o que voltou para você.

E a ordem?

As cidades vieram na ordem em que apareceram pela primeira vez na tabela (Teresina, do cliente 1; São Paulo, do cliente 3…). Mas o SQL não promete ordem nenhuma no resultado, com ou sem DISTINCT. Se a ordem importa (em ordem alfabética, por exemplo), peça com ORDER BY, assunto da aula ORDER BY.


3. Mais perguntas que o DISTINCT responde

Toda pergunta do tipo "quais são os … diferentes?" é um caso para o DISTINCT.

Quais cargos existem na loja?

SELECT DISTINCT cargo FROM funcionarios;

São 8 funcionários e 5 cargos. Repare que Vendedor e Vendedora aparecem separados: para o banco, são dois textos diferentes. O DISTINCT compara os valores letra por letra; ele não sabe que as duas palavras querem dizer quase a mesma coisa. Pelo mesmo motivo, 'Teresina' e 'teresina' contariam como duas cidades: no SQLite, maiúsculas e minúsculas fazem diferença nos dados (mais sobre isso em WHERE).

De quais países vêm os fornecedores?

SELECT DISTINCT pais FROM fornecedores;

Quais clientes já fizeram pelo menos um pedido?

A tabela pedidos tem 90 pedidos, e a coluna cliente_id diz de qual cliente é cada um. Quem comprou várias vezes aparece várias vezes. Com DISTINCT, cada cliente aparece uma vez:

SELECT DISTINCT cliente_id FROM pedidos;

São 26 clientes, os de número 1 a 26. Como a loja tem 30 clientes, quatro deles (27, 28, 29 e 30) ainda não fizeram nenhum pedido. Descobrir quem são eles pelo nome é trabalho para a aula LEFT JOIN.

Missão: a loja manda catálogos por estado. De quais estados são os clientes? Mostre cada estado uma vez só.

SELECT estado FROM clientes;
SELECT DISTINCT estado FROM clientes;

4. DISTINCT com várias colunas

Esta é a parte que mais confunde. Com mais de uma coluna, o DISTINCT não olha cada coluna separada: ele olha a linha inteira. Duas linhas só são "repetidas" se forem iguais em todas as colunas pedidas.

A Ana quer saber, em cada estado, se há clientes VIP (vip = 1), comuns (vip = 0) ou os dois:

SELECT DISTINCT estado, vip FROM clientes;

Vieram 7 linhas. O PI aparece duas vezes, PI|1 e PI|0, e não é repetição: as duas linhas são diferentes na coluna vip. Lendo o resultado: PI, SP e CE têm clientes VIP e comuns; PE só tem clientes comuns (por isso não há a linha PE|1, e são 7, não 8).

Linhas do resultado sem DISTINCTSão repetidas?
PI|0 e PI|0Sim: iguais nas duas colunas. Fica uma.
PI|0 e PI|1Não: o estado é igual, mas o vip é diferente. Ficam as duas.
PI|0 e CE|0Não: o vip é igual, mas o estado é diferente. Ficam as duas.

Quando o DISTINCT não tira nada

Se uma das colunas pedidas nunca se repete, nenhuma linha é igual a outra, e o DISTINCT não tem o que tirar. O id de cada cliente é único, então:

SELECT DISTINCT id, cidade FROM clientes;

Continuam as 30 linhas, com Teresina repetida, porque cada linha tem um id diferente. Para ver as cidades sem repetição, peça só a cidade.

Missão: em quais cidades ficam os fornecedores da loja? Esta consulta trouxe uma cidade repetida (Teresina aparece duas vezes) porque pede também o nome. Mostre cada cidade uma vez só.

SELECT DISTINCT nome, cidade FROM fornecedores;
SELECT DISTINCT cidade FROM fornecedores;

5. DISTINCT e o NULL

Lembra dos fornecedores estrangeiros, que não têm estado (NULL)? Veja o que o DISTINCT faz com eles:

SELECT DISTINCT estado FROM fornecedores;

Os dois NULL (de Portugal e da Argentina) viraram uma linha só. Para o DISTINCT, todos os "sem valor" contam como iguais entre si. O mesmo acontece com os 3 clientes sem email:

SELECT DISTINCT email FROM clientes;

São 28 linhas: os 27 emails diferentes e uma linha NULL no lugar dos três clientes sem email. Guarde isso: em outras partes do SQL o NULL se comporta de outro jeito, e a aula O Valor NULL explica cada caso.


Formas diferentes de fazer a mesma coisa

DISTINCT × GROUP BY

Mais adiante você vai aprender o GROUP BY, que junta as linhas em grupos. Pedir os grupos de cidade dá a mesma lista de cidades:

SELECT cidade FROM clientes GROUP BY cidade;

As mesmas 8 cidades (aqui, por acaso, em ordem alfabética; de novo, só o ORDER BY garante a ordem). O GROUP BY serve para muito mais coisas, como contar quantos clientes há em cada cidade; é a aula GROUP BY.

Contar quantos são os diferentes

E se a pergunta for "quantas cidades?", e não "quais"? Dá para contar sem listar, com a função COUNT (aula COUNT()). Uma prévia:

SELECT COUNT(cidade), COUNT(DISTINCT cidade) FROM clientes;

A primeira conta conta as cidades com repetição (30, uma por cliente); a segunda conta só as diferentes (8).

ALL: o contrário de DISTINCT

Existe também SELECT ALL ("todos"), que mantém as repetições. Como esse já é o comportamento normal, quase ninguém escreve: SELECT ALL cidade FROM clientes; é igual a SELECT cidade FROM clientes;, com as 30 linhas.

PerguntaUse
Quais são os valores diferentes?SELECT DISTINCT cidade FROM clientes;
Quantos são os valores diferentes?SELECT COUNT(DISTINCT cidade) FROM clientes;
Quantos clientes há em cada cidade?GROUP BY (aula GROUP BY)
Quero todas as linhas, com repetiçãoSELECT cidade FROM clientes; (o ALL é o normal)

Quando dá errado

DISTINCT no meio da lista

A Ana queria todas as cidades e, ao lado, os estados sem repetir:

SELECT cidade, DISTINCT estado FROM clientes;

near "DISTINCT": syntax error. O DISTINCT não vale para uma coluna só: ele vale para a linha inteira, e por isso tem um lugar fixo, logo depois do SELECT. No meio da lista, o banco não sabe o que fazer com ele. Como consertar: SELECT DISTINCT cidade, estado FROM clientes;, sabendo que o DISTINCT vai olhar as duas colunas juntas.

Achar que os parênteses limitam o DISTINCT

Outra tentativa comum é pôr a coluna entre parênteses, como se o DISTINCT fosse valer só para ela:

SELECT DISTINCT (cidade), estado FROM clientes;

Não dá erro, mas também não faz o que parece. O parêntese em volta de cidade não muda nada (é como escrever (2) em vez de 2 numa conta), e o DISTINCT continua olhando a linha inteira, cidade e estado. O resultado é igual ao de SELECT DISTINCT cidade, estado.

O DISTINCT "não funcionou"
SELECT DISTINCT nome, cidade FROM clientes;

Vieram as 30 linhas, e Teresina continua repetida. O DISTINCT funcionou, sim: não existem dois clientes com o mesmo nome e a mesma cidade, então não havia linha repetida para tirar. Como consertar: peça só as colunas que você quer sem repetição. Se o DISTINCT "não fez nada", olhe se a lista tem uma coluna que quase nunca se repete, como id, nome ou email.

Esqueceu a coluna
SELECT DISTINCT FROM clientes;

near "FROM": syntax error, o mesmo erro de um SELECT FROM sem nada no meio: depois do DISTINCT o banco esperava a lista de colunas.

Nos outros bancos

O SELECT DISTINCT desta aula funciona igual no MySQL, no PostgreSQL e no SQL Server. O PostgreSQL tem, além dele, uma extensão própria, o DISTINCT ON, que não faz parte do SQL padrão e não existe no SQLite. Ele guarda só a primeira linha de cada grupo de valores iguais nas colunas entre parênteses, e é usado junto com ORDER BY. Um exemplo, só para ilustrar (não roda no SQLite):

SELECT DISTINCT ON (cidade) cidade, nome
FROM clientes
ORDER BY cidade, nome;

No PostgreSQL, isso mostraria uma linha por cidade, com o primeiro nome em ordem alfabética de cada uma.


Referência rápida

EscritaO que faz
SELECT DISTINCT coluna FROM tabela;Cada valor da coluna uma vez só
SELECT DISTINCT col1, col2 FROM tabela;Cada combinação de col1 e col2 uma vez só
SELECT ALL coluna FROM tabela;Com repetições (o normal; o ALL é opcional)
SELECT COUNT(DISTINCT coluna) FROM tabela;Quantos valores diferentes existem
NULL no DISTINCTTodos os NULL viram uma linha só

Exercícios

1. Sem repetir

Complete para mostrar cada cargo uma vez só:

SELECT cargo FROM funcionarios;

2. Quantas linhas vêm em SELECT DISTINCT estado FROM clientes;, se os 30 clientes são dos estados PI, SP, CE e PE?

3. Em SELECT DISTINCT estado, vip FROM clientes;, as linhas PI|0 e PI|1…

4. Onde o DISTINCT deve ser escrito?

5. A tabela tem 3 clientes sem email (NULL). No resultado de SELECT DISTINCT email FROM clientes;, quantas linhas NULL aparecem?

Missão final: quem já vendeu?

Missão: a tabela pedidos tem a coluna funcionario_id, com o número do funcionário que atendeu cada pedido. A gerente quer saber quais funcionários já atenderam algum pedido. Mostre só essa coluna, cada número uma vez.

SELECT funcionario_id FROM pedidos;
SELECT DISTINCT funcionario_id FROM pedidos;

Dos 8 funcionários, 6 aparecem (os números 2 a 7). Faltam a gerente, Marta (1), e o estoquista, Davi (8), que não atendem pedidos. Confira com SELECT * FROM funcionarios;.


Resumo

  • Um SELECT comum mostra uma linha para cada linha da tabela, com repetições.
  • SELECT DISTINCT ("distintos") tira as linhas repetidas do resultado: cada valor aparece uma vez. A tabela não muda.
  • O DISTINCT vem logo depois do SELECT e vale para a linha inteira: com várias colunas, só some a linha igual em todas elas.
  • Com uma coluna que nunca se repete (como id), o DISTINCT não tem o que tirar.
  • Os NULL viram uma linha só. Textos são comparados exatamente: Vendedor e Vendedora são diferentes.
  • O SQL não promete a ordem do resultado; para ordenar, use ORDER BY.