1. Qué es
DISTINCT elimina filas de resultado repetidas. Es el paso 6 del orden-logico-de-ejecucion: actúa sobre lo que el SELECT ya produjo, no sobre la tabla.
Y ahí está todo lo importante del tema, en dos frases:
DISTINCTcompara la fila entera delSELECT, no la primera columna.DISTINCTes a veces la respuesta y muchas veces una tirita. Cuando aparece para "arreglar" filas duplicadas que no esperabas, casi siempre está tapando un error en elFROM.
Este último punto es el que hace que este tema cierre el bloque 2 y no lo abra.
2. Sintaxis
SELECT DISTINCT columna1, columna2 FROM tabla; -- filas únicas
SELECT count(DISTINCT columna) FROM tabla; -- cuántos valores distintos
SELECT DISTINCT ON (columna) * FROM tabla ORDER BY columna, otra; -- solo PostgreSQL
DISTINCT va justo después de SELECT y afecta a todas las columnas. No existe SELECT col1, DISTINCT col2.
3. Ejemplos sobre Northwind
Los valores distintos de una columna:
SELECT DISTINCT
country
FROM
customers
ORDER BY
country;
country
-----------
Argentina
Austria
Belgium
Brazil
...
21 países para 91 clientes.
Contar distintos sin listarlos:
SELECT
count(*) AS filas,
count(DISTINCT country) AS paises,
count(DISTINCT city) AS ciudades
FROM
customers;
filas | paises | ciudades
-------+--------+----------
91 | 21 | 69
Esas tres cifras juntas son un perfilado: 91 clientes repartidos en 69 ciudades y 21 países. Con eso ya sabes que la ciudad casi identifica al cliente y el país no.
3.1 DISTINCT mira la fila entera
SELECT DISTINCT
country,
city
FROM
customers
ORDER BY
country,
city;
country | city
-----------+--------------
Argentina | Buenos Aires
Austria | Graz
Austria | Salzburg
Belgium | Bruxelles
Belgium | Charleroi
69 filas, no 21. Austria sale dos veces porque las parejas son distintas. Si esperabas 21, estabas pensando en DISTINCT country y escribiste otra cosa.
3.2 DISTINCT sí junta los NULL
SELECT DISTINCT
region
FROM
customers
ORDER BY
region NULLS LAST;
Devuelve 19 filas: 18 regiones más una fila vacía. Pero:
SELECT count(DISTINCT region) FROM customers; -- 18
DISTINCT trata todos los NULL como uno solo y los devuelve; count(DISTINCT ...) los ignora. No es contradictorio —count ignora nulos siempre, null-y-la-logica-de-tres-valores— pero explica por qué la lista tiene una fila más que el conteo. Si comparas las dos cifras sin saberlo, parecen un error.
3.3 DISTINCT vs GROUP BY
SELECT DISTINCT country FROM customers;
SELECT country FROM customers GROUP BY country;
Idénticas: mismo resultado y mismo plan de ejecución. La diferencia es de intención:
DISTINCTdice "quita repetidos".GROUP BYdice "agrupa", y deja la puerta abierta a añadir uncount(*)o unsum().
Usa DISTINCT cuando solo quieras la lista, y GROUP BY en cuanto vayas a agregar algo. Casi siempre acabas queriendo agregar algo.
3.4 DISTINCT ON — el atajo de PostgreSQL
El último pedido de cada cliente:
SELECT DISTINCT ON (customer_id)
customer_id,
order_id,
order_date
FROM
orders
ORDER BY
customer_id,
order_date DESC,
order_id DESC;
customer_id | order_id | order_date
-------------+----------+------------
ALFKI | 11011 | 1998-04-09
ANATR | 10926 | 1998-03-04
ANTON | 10856 | 1998-01-28
AROUT | 11016 | 1998-04-10
Se queda con la primera fila de cada grupo, y "primera" la define el ORDER BY.
Dos reglas que no son negociables:
- El
ORDER BYdebe empezar por las mismas columnas delDISTINCT ON. Si no, error. - Lo que venga después decide cuál se queda. Sin
order_date DESCte quedas con un pedido cualquiera del cliente, no con el último.
DISTINCT ON no existe en el estándar SQL ni en SQL Server. Es de las cosas más cómodas de PostgreSQL y de las menos portables. El equivalente universal es ROW_NUMBER() (ranking-row-number-rank-ntile).
4. Errores comunes
- Creer que
DISTINCTaplica solo a la primera columna. Aplica a la fila entera. - Usar
DISTINCTpara tapar unJOINque multiplica filas. Ver arriba. Arregla elFROM. sum(DISTINCT x)oavg(DISTINCT x). Casi siempre da un número equivocado y creíble.- Comparar
DISTINCT colconcount(DISTINCT col)y asustarse por la diferencia de uno. Es elNULL. DISTINCT ONsin elORDER BYcorrecto. O da error, o te devuelve una fila arbitraria del grupo.- Poner
DISTINCT"por si acaso". Cuesta una ordenación o un hash sobre todo el resultado, y sobre todo te quita el aviso: si sobran filas, quieres enterarte.
5. Diferencias con SQL Server
| PostgreSQL | SQL Server | |
|---|---|---|
| Filas únicas | SELECT DISTINCT |
SELECT DISTINCT — igual |
| Contar distintos | count(DISTINCT col) |
COUNT(DISTINCT col) — igual |
| Primera fila por grupo | DISTINCT ON |
❌ No existe → ROW_NUMBER() OVER (PARTITION BY ...) |
count(DISTINCT) con ventana |
No permitido | No permitido |
DISTINCT ON es el único punto de divergencia, y es grande: una consulta con DISTINCT ON no se puede pegar en SQL Server. Si el material tiene que valer para los dos motores, escribe la versión con ROW_NUMBER().
6. Ejercicios
- Los cargos (
title) distintos que existen enemployees, y cuántos hay. - Cuántos países distintos aparecen como destino de un pedido (
ship_country), y si coinciden con los países de los clientes. - Las parejas país-ciudad distintas de
suppliers, ordenadas. - El pedido más antiguo de cada cliente, en una sola consulta.
- Explica por qué estas dos consultas dan números distintos y cuál es la correcta para "cuántos clientes han comprado":
sql SELECT count(*) FROM orders; SELECT count(DISTINCT customer_id) FROM orders;
7. Pregunta de negocio
Te piden "cuántos clientes distintos compraron en 1997 y de qué países". Un compañero ya la escribió y le salen 89 clientes, pero la empresa solo tiene 91 clientes en total y sabe que muchos no compraron ese año. ¿Qué pasó?