0Pricing
SQL Academy · Lección

DISTINCT ON de PostgreSQL

Elija una fila por grupo

DISTINCT ON de PostgreSQL es una lección gratuita de SQL Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de SQL Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de SQL Academy incluye 4 lecciones en total.

¿Qué es DISTINCT ON?

PostgreSQL ofrece una potente extensión de la palabra clave estándar DISTINCT llamada DISTINCT ON. Mientras que DISTINCT elimina las filas completamente duplicadas, DISTINCT ON permite elegir exactamente una fila por grupo según una o varias columnas que usted seleccione.

Puede entenderlo así: «Para cada valor único de esta columna, deme una fila». Es extremadamente útil cuando quiere obtener el pedido más reciente de cada cliente, la puntuación más alta de cada estudiante o el primer evento de cada categoría.

Sintaxis básica de DISTINCT ON

La sintaxis coloca DISTINCT ON (column) justo después de SELECT. La columna que aparece entre paréntesis define la agrupación: PostgreSQL devolverá una fila por cada valor único de esa columna.

El ejemplo siguiente devuelve una fila por cada customer_id de una tabla de pedidos. PostgreSQL determina qué fila devolver según la cláusula ORDER BY que aparece a continuación.

SELECT DISTINCT ON (customer_id)
  customer_id,
  order_id,
  order_date,
  total_amount
FROM orders
ORDER BY customer_id, order_date DESC;

Configuración de tablas de ejemplo

Vamos a crear una tabla orders sencilla e insertar algunas filas de ejemplo para probar DISTINCT ON. Tenemos tres clientes, cada uno con varios pedidos realizados en fechas diferentes.

CREATE TABLE orders (
  order_id      SERIAL PRIMARY KEY,
  customer_id   INT,
  order_date    DATE,
  total_amount  NUMERIC(10, 2)
);

INSERT INTO orders (customer_id, order_date, total_amount) VALUES
  (1, '2024-01-05', 120.00),
  (1, '2024-03-12', 85.50),
  (1, '2024-06-20', 200.00),
  (2, '2024-02-14', 45.00),
  (2, '2024-05-30', 310.00),
  (3, '2024-04-01', 75.00);

Pedido más reciente por cliente

Un caso de uso muy común es encontrar el pedido más reciente de cada cliente. Al ordenar order_date DESC dentro de cada grupo de customer_id, DISTINCT ON selecciona la fila con la fecha más reciente.

Observe que la cláusula ORDER BY debe comenzar con las mismas columnas que aparecen en DISTINCT ON. Este es un requisito de PostgreSQL.

SELECT DISTINCT ON (customer_id)
  customer_id,
  order_id,
  order_date,
  total_amount
FROM orders
ORDER BY customer_id, order_date DESC;

Pedido más antiguo por cliente

Para obtener en su lugar el primer pedido (el más antiguo) de cada cliente, solo tiene que cambiar la dirección de ordenación a ASC. La única diferencia es el orden de las filas dentro de cada grupo: DISTINCT ON siempre selecciona la primera fila después de ordenar.

SELECT DISTINCT ON (customer_id)
  customer_id,
  order_id,
  order_date,
  total_amount
FROM orders
ORDER BY customer_id, order_date ASC;

La regla de ORDER BY

Regla importante: al usar DISTINCT ON (col), la cláusula ORDER BY debe comenzar con las mismas columnas que aparecen dentro de DISTINCT ON. Si no es así, PostgreSQL generará un error.

Después de las columnas de agrupación, puede añadir cualquier criterio de ordenación adicional para controlar qué fila se selecciona dentro de cada grupo.

-- Correct: ORDER BY starts with the DISTINCT ON column
SELECT DISTINCT ON (customer_id)
  customer_id, order_date, total_amount
FROM orders
ORDER BY customer_id, total_amount DESC;

-- This would cause an error:
-- ORDER BY order_date DESC  (missing customer_id at the start)

Puntuación más alta por estudiante

A continuación se muestra otro ejemplo práctico con una tabla test_scores. Queremos obtener la puntuación más alta que haya conseguido cada estudiante. Al ordenar score DESC dentro de cada grupo de estudiantes, DISTINCT ON devuelve únicamente la fila con la puntuación más alta de cada estudiante.

CREATE TABLE test_scores (
  id         SERIAL PRIMARY KEY,
  student_id INT,
  subject    VARCHAR(50),
  score      INT,
  taken_on   DATE
);

INSERT INTO test_scores (student_id, subject, score, taken_on) VALUES
  (101, 'Math',    92, '2024-02-10'),
  (101, 'Math',    78, '2024-04-15'),
  (102, 'Math',    85, '2024-02-10'),
  (102, 'Math',    91, '2024-04-15'),
  (103, 'Math',    67, '2024-02-10');

SELECT DISTINCT ON (student_id)
  student_id, subject, score, taken_on
FROM test_scores
ORDER BY student_id, score DESC;

DISTINCT ON con varias columnas

Puede agrupar por más de una columna indicando varias columnas dentro de DISTINCT ON. Esto devuelve una fila por cada combinación única de esas columnas.

El ejemplo siguiente selecciona la puntuación más alta de cada estudiante por asignatura, tratando cada par (estudiante, asignatura) como un grupo independiente.

INSERT INTO test_scores (student_id, subject, score, taken_on) VALUES
  (101, 'Science', 88, '2024-03-01'),
  (101, 'Science', 95, '2024-05-20'),
  (102, 'Science', 72, '2024-03-01');

SELECT DISTINCT ON (student_id, subject)
  student_id, subject, score, taken_on
FROM test_scores
ORDER BY student_id, subject, score DESC;

Filtrar con WHERE

DISTINCT ON funciona de forma natural junto con las cláusulas WHERE. El filtro se aplica primero y, después, DISTINCT ON selecciona una fila por grupo a partir de los resultados filtrados.

Aquí buscamos el pedido más reciente de cada cliente, pero solo entre los pedidos superiores a 100.

SELECT DISTINCT ON (customer_id)
  customer_id,
  order_id,
  order_date,
  total_amount
FROM orders
WHERE total_amount > 100
ORDER BY customer_id, order_date DESC;

DISTINCT ON frente a GROUP BY

Tanto DISTINCT ON como GROUP BY pueden producir una fila por grupo, pero tienen objetivos diferentes:

  • GROUP BY combina las filas y requiere funciones de agregación (SUM, MAX, etc.) para las columnas que no forman parte de la agrupación.
  • DISTINCT ON conserva una fila existente real; todas sus columnas están disponibles sin agregación.

Use GROUP BY cuando necesite valores agregados. Use DISTINCT ON cuando necesite todos los datos de una fila específica dentro de cada grupo.

-- GROUP BY: only aggregated columns allowed
SELECT customer_id, MAX(order_date) AS latest_date
FROM orders
GROUP BY customer_id;

-- DISTINCT ON: returns the whole row for that latest date
SELECT DISTINCT ON (customer_id)
  customer_id, order_id, order_date, total_amount
FROM orders
ORDER BY customer_id, order_date DESC;

Usar DISTINCT ON en una subconsulta

A veces necesita aplicar filtros u ordenaciones adicionales sobre el resultado de DISTINCT ON. Como el ORDER BY externo está vinculado a la columna de agrupación, puede envolver la consulta en una subconsulta (o CTE) para aplicar una ordenación diferente al resultado final.

En este ejemplo, primero se selecciona el pedido más reciente de cada cliente y, después, el resultado final se ordena de forma descendente por total_amount.

SELECT *
FROM (
  SELECT DISTINCT ON (customer_id)
    customer_id,
    order_id,
    order_date,
    total_amount
  FROM orders
  ORDER BY customer_id, order_date DESC
) AS latest_orders
ORDER BY total_amount DESC;

Comprobación rápida

Compruebe su comprensión de DISTINCT ON. Lea detenidamente la consulta siguiente y elija la respuesta que describa mejor lo que devuelve.

SELECT DISTINCT ON (department_id) department_id, employee_name, salary FROM employees ORDER BY department_id, salary DESC;

Resumen de la lección

¡Excelente trabajo! Este es un resumen de lo que ha aprendido sobre PostgreSQL DISTINCT ON:

  • DISTINCT ON (col) devuelve exactamente una fila por cada valor único de las columnas especificadas.
  • La cláusula ORDER BY debe comenzar con las mismas columnas que aparecen en DISTINCT ON; así se controla qué fila se selecciona de cada grupo.
  • Puede usar varias columnas: DISTINCT ON (col1, col2) agrupa por la combinación de ambas.
  • A diferencia de GROUP BY, DISTINCT ON devuelve una fila real con todas sus columnas originales, sin necesidad de agregación.
  • Envuelva la consulta en una subconsulta cuando necesite ordenar el resultado final por una columna diferente.

DISTINCT ON es una función específica de PostgreSQL y una de las formas más elegantes de resolver problemas en los que hay que «elegir una fila por grupo».

Preguntas frecuentes

¿La lección «DISTINCT ON de PostgreSQL» es gratis?

Sí — el texto completo de «DISTINCT ON de PostgreSQL» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de SQL Academy, actualiza a CoddyKit PRO. El curso de SQL Academy incluye 4 lecciones en total.

¿Qué aprenderé en «DISTINCT ON de PostgreSQL»?

Elija una fila por grupo Practicas SQL Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar SQL Academy?

No se requiere experiencia previa. SQL Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «DISTINCT ON de PostgreSQL»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de SQL Academy?

Sí. Cada lección de SQL Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Conceptos básicos de SELECT DISTINCT
  2. DISTINCT en varias columnas
  3. DISTINCT ON de PostgreSQL
  4. Recuento de valores únicos
← Volver a SQL Academy