COUNT(DISTINCT coluna) conta quantos valores diferentes uma coluna contém: um valor que aparece dez vezes conta uma vez só, e NULLs não contam. Os exemplos funcionam no PostgreSQL, MySQL, SQLite e SQL Server.
Como usar COUNT DISTINCT
Coloque DISTINCT dentro de COUNT(), antes da coluna ou expressão a ser contada:
COUNT(DISTINCT expression)
Fica mais fácil de entender comparando com as outras duas formas de COUNT. COUNT(*) conta linhas, COUNT(column) conta as linhas em que a coluna não é NULL, e COUNT(DISTINCT column) conta os valores diferentes não NULL:
-- Input: orders
-- order_id | customer_id
-- ---------+------------
-- 1 | 1042
-- 2 | 1077
-- 3 | 1042
-- 4 | NULL
SELECT COUNT(*) AS all_rows,
COUNT(customer_id) AS with_customer,
COUNT(DISTINCT customer_id) AS customers
FROM orders;
-- Output:
-- all_rows | with_customer | customers
-- ---------+---------------+----------
-- 4 | 3 | 2
Quatro pedidos vieram de dois clientes: o 1042 fez dois pedidos, e o pedido 4 não tem cliente nenhum.
Regras importantes
- NULLs não são contados. Se um valor ausente deve contar como mais um, some você mesmo:
-- Input: the orders table above
SELECT COUNT(DISTINCT customer_id)
+ MAX(CASE WHEN customer_id IS NULL THEN 1 ELSE 0 END) AS customers_and_guests
FROM orders;
-- Output: 3
-
MySQL e SQL Server ignoram maiúsculas e minúsculas por padrão, então contam
'SQL'e'sql'como um único valor. ConteLOWER(tag)quando a diferença entre maiúsculas e minúsculas não importar:
-- Input: tags
-- post_id | tag
-- --------+---------
-- 1 | SQL
-- 2 | sql
-- 3 | Postgres
SELECT COUNT(DISTINCT tag) FROM tags;
-- Output: 3 (2 in MySQL and SQL Server)
SELECT COUNT(DISTINCT LOWER(tag)) FROM tags;
-- Output: 2
-
DISTINCT também funciona dentro de
SUMeAVG, mas descarta valores repetidos, não linhas repetidas. Dois produtos diferentes com o mesmo preço são somados uma vez só:
-- Input: order_lines
-- product | price
-- ---------+------
-- Pen | 2.00
-- Pencil | 2.00
-- Notebook | 5.00
SELECT SUM(price) AS total, SUM(DISTINCT price) AS distinct_total FROM order_lines;
-- Output:
-- total | distinct_total
-- ------+---------------
-- 9.00 | 7.00
Sintaxe alternativa
COUNT(DISTINCT ...) aceita uma coluna. Para contar as combinações diferentes de várias colunas, conte as linhas de uma subconsulta com DISTINCT. PostgreSQL e MySQL também têm atalhos:
-- Input: orders
-- order_id | customer_id | product_id
-- ---------+-------------+-----------
-- 1 | 1 | 23
-- 2 | 12 | 3
-- 3 | 1 | 23
-- 4 | 12 | 5
SELECT COUNT(*) FROM (SELECT DISTINCT customer_id, product_id FROM orders) AS pairs;
-- Output: 3
-- PostgreSQL
SELECT COUNT(DISTINCT (customer_id, product_id)) FROM orders;
-- Output: 3
-- MySQL
SELECT COUNT(DISTINCT customer_id, product_id) FROM orders;
-- Output: 3
Você também vai ver as colunas juntadas em uma única string com CONCAT(). É preciso um separador: sem ele, o cliente 1 com o produto 23 e o cliente 12 com o produto 3 viram ambos '123':
-- Input: the orders table above
SELECT COUNT(DISTINCT CONCAT(customer_id, product_id)) FROM orders;
-- Output: 2
SELECT COUNT(DISTINCT CONCAT(customer_id, '_', product_id)) FROM orders;
-- Output: 3
Uma contagem distinta exata precisa ordenar ou gerar hash de cada valor, o que fica lento em tabelas muito grandes. O SQL Server tem APPROX_COUNT_DISTINCT(), que é mais rápido e fica a até 2% da contagem exata em 97% das vezes:
-- SQL Server
-- Input: the orders table above
SELECT APPROX_COUNT_DISTINCT(customer_id) AS customers FROM orders;
-- Output: 2
Quando usar COUNT DISTINCT?
Use COUNT DISTINCT quando a pergunta for “quantos … diferentes?” em vez de “quantas linhas?”. A maioria dessas perguntas se encaixa em um destes quatro casos.
Contar visitantes, clientes ou produtos únicos
Um log de visitas, pedidos ou vendas registra o mesmo visitante, cliente ou produto várias vezes. COUNT DISTINCT no ID transforma essas linhas em uma contagem de pessoas ou itens.
Contar valores únicos em cada grupo
Adicione GROUP BY e você obtém uma contagem distinta por grupo: alunos diferentes por curso, produtos diferentes por fornecedor, clientes diferentes por mês.
Contar combinações únicas de colunas
Às vezes duas linhas só são “iguais” quando duas colunas coincidem: o mesmo usuário com o mesmo tipo de problema, ou a mesma rota entre dois aeroportos. Conte as combinações com uma das formas de várias colunas em “Sintaxe alternativa”.
Contar valores únicos que atendem a uma condição
Coloque uma expressão CASE dentro de COUNT(DISTINCT ...) para contar só algumas linhas. O CASE retorna NULL para as linhas que você não quer, e NULLs não são contados, então uma única consulta pode retornar várias contagens filtradas lado a lado.
Exemplos reais de COUNT DISTINCT
Usuários ativos mensais
Conte os usuários que fizeram qualquer coisa em setembro, não importa quantas vezes tenham voltado:
-- Input: events
-- event_id | user_id | event_date
-- ---------+---------+-----------
-- 1 | 301 | 2026-08-30
-- 2 | 302 | 2026-09-02
-- 3 | 302 | 2026-09-15
-- 4 | 305 | 2026-09-21
-- 5 | 302 | 2026-10-01
SELECT COUNT(DISTINCT user_id) AS active_users
FROM events
WHERE event_date >= '2026-09-01' AND event_date < '2026-10-01';
-- Output: 2
Produtos vendidos por fornecedor
COUNT(*) dá o número de vendas de cada fornecedor, e COUNT(DISTINCT product) quantos produtos diferentes essas vendas abrangeram:
-- Input: sales
-- vendor | product | color
-- -----------+----------+------
-- Acme | Mug | Red
-- Acme | Mug | Blue
-- Acme | Mug | Red
-- Acme | Tote Bag | Red
-- Brightside | Notebook | Black
SELECT vendor, COUNT(*) AS sales, COUNT(DISTINCT product) AS products
FROM sales
GROUP BY vendor;
-- Output:
-- vendor | sales | products
-- -----------+-------+---------
-- Acme | 4 | 2
-- Brightside | 1 | 1
Rotas que uma companhia aérea opera
Uma rota é uma origem e um destino juntos. Dois voos de LHR para JFK são uma rota, mas JFK para LHR é outra:
-- Input: flights
-- flight_no | origin | destination
-- ----------+--------+------------
-- 101 | LHR | JFK
-- 105 | LHR | JFK
-- 102 | JFK | LHR
-- 301 | LHR | LAX
SELECT COUNT(*) AS routes
FROM (SELECT DISTINCT origin, destination FROM flights) AS r;
-- Output: 3
Clientes pelo preço do que compraram
Conte os clientes que compraram os produtos 100 a 200 e depois divida-os pelo preço dos pedidos. O cliente 7 fez dois pedidos baratos, mas conta uma vez, e o produto do cliente 15 está fora do intervalo:
-- Input: orders
-- order_id | customer_id | product_id | price
-- ---------+-------------+------------+-------
-- 1 | 7 | 105 | 25.00
-- 2 | 7 | 142 | 40.00
-- 3 | 9 | 150 | 120.00
-- 4 | 12 | 188 | 310.00
-- 5 | 15 | 260 | 30.00
SELECT
COUNT(DISTINCT customer_id) AS customers,
COUNT(DISTINCT CASE WHEN price BETWEEN 1 AND 50 THEN customer_id END) AS low_spenders,
COUNT(DISTINCT CASE WHEN price BETWEEN 51 AND 150 THEN customer_id END) AS mid_spenders,
COUNT(DISTINCT CASE WHEN price > 150 THEN customer_id END) AS high_spenders
FROM orders
WHERE product_id BETWEEN 100 AND 200;
-- Output:
-- customers | low_spenders | mid_spenders | high_spenders
-- ----------+--------------+--------------+--------------
-- 3 | 1 | 1 | 1
Um cliente com pedidos em duas faixas de preço é contado em ambas.
Leitura adicional sobre COUNT DISTINCT
Neste blog:
-
Guia de SQL GROUP BY:
COUNT,SUMeAVGpara cada grupo - Guia para encontrar duplicatas em SQL: encontre os valores que aparecem mais de uma vez
- Guia para remover duplicatas em SQL: exclua as cópias extras
- Guia da instrução CASE em SQL: as condições por trás das contagens condicionais
-
Having vs Where em SQL: filtre por uma contagem com
HAVING - Cheat sheet de SQL: agregações e o resto do SQL em uma página
Documentação oficial:
- PostgreSQL: expressões de agregação
- MySQL: COUNT(DISTINCT)
- SQLite: count()
- SQL Server: COUNT e APPROX_COUNT_DISTINCT
Beekeeper Studio é um cliente de banco de dados gratuito e open source
A melhor ferramenta de consultas e edição de SQL que já usei. Tem tudo o que preciso para gerenciar meu banco de dados. - ⭐⭐⭐⭐⭐ Mit
O Beekeeper Studio é rápido, intuitivo e fácil de usar. Ele suporta vários bancos de dados e funciona muito bem no Windows, Mac e Linux.
O que os usuários dizem sobre o Beekeeper Studio
"O Beekeeper Studio substituiu completamente meu antigo fluxo de trabalho com SQL. É rápido, intuitivo e torna o trabalho com bancos de dados prazeroso de novo."
"Já experimentei muitas GUIs de banco de dados, mas o Beekeeper encontra o equilíbrio perfeito entre recursos e simplicidade. Simplesmente funciona."