Error SQL · DISTINCT y ordenación

DISTINCT y ORDER BY fallan al ordenar por una columna no seleccionada

Una consulta puede funcionar sin DISTINCT y fallar en cuanto intentas eliminar duplicados: el ORDER BY usa una columna que ya no forma parte del resultado. PostgreSQL, SQL Server y MySQL con sus comprobaciones de agrupación estrictas rechazan patrones comunes porque, después de deduplicar, no siempre existe un único valor oculto con el que ordenar cada fila resultante.

Lectura: 15–20 minDiferencias por motorPráctica con pistas

El síntoma: añades DISTINCT y ORDER BY deja de ser válido

Supón que quieres una lista de ciudades sin duplicados, pero además intentas ordenarlas por el identificador del cliente:

Patrón problemático en motores estrictos
SELECT DISTINCT ciudad
FROM clientes
ORDER BY id;

Sin DISTINCT, ordenar por id aunque no lo muestres suele ser válido. Con DISTINCT ciudad, varias filas de clientes pueden convertirse en una sola ciudad. Entonces aparece una pregunta que la consulta no responde: si Madrid pertenece a los clientes 1, 3, 6 y 9, ¿qué id debería representar a la única fila «Madrid» al ordenar?

Por qué DISTINCT vuelve ambiguo un ORDER BY oculto

DISTINCT define la identidad del resultado a partir de las expresiones seleccionadas. Si seleccionas solo ciudad, todas las filas con el mismo valor se reducen a una. Una columna que no forma parte de esa identidad puede tener varios valores dentro del grupo de filas que acaba colapsándose.

idciudad
1Madrid
3Madrid
6Madrid
9Madrid

Después de SELECT DISTINCT ciudad queda una sola fila «Madrid». Ordenarla por un id oculto sería ambiguo si no has definido qué id representa al grupo. Por eso la corrección no consiste simplemente en «hacer feliz al motor»: debes expresar qué orden quieres.

Error frecuente: añadir la columna a SELECT puede cambiar lo que DISTINCT significa

Corrección aparente
SELECT DISTINCT ciudad, id
FROM clientes
ORDER BY id;

Esta consulta ya no pide ciudades únicas. Pide combinaciones únicas de ciudad + id. Como id es único, prácticamente cada cliente vuelve a ser una fila distinta. Si tu objetivo era deduplicar ciudades, has cambiado la pregunta.

Regla práctica: solo añade la expresión de orden al SELECT DISTINCT cuando forme parte legítima de la identidad que quieres devolver o cuando sea una función determinista de esa identidad y no altere la deduplicación.

Tres correcciones según la intención real

1. Si solo quieres una lista ordenada de valores únicos, ordena por el propio valor

Ciudades únicas en orden alfabético
SELECT DISTINCT ciudad
FROM clientes
ORDER BY ciudad;
Resultado comprobado localmente con SQLite
ciudad
A Coruña
Bilbao
Madrid
Sevilla
Valencia
Zaragoza

2. Si quieres ordenar cada valor único por una propiedad del grupo, define esa propiedad

Por ejemplo, «ciudades ordenadas por el primer cliente registrado en la tabla» sí tiene una regla concreta. Puedes agrupar por ciudad y ordenar por el menor identificador:

Ordenar el grupo por una medida definida
SELECT ciudad
FROM clientes
GROUP BY ciudad
ORDER BY MIN(id), ciudad;
Resultado comprobado localmente
ciudadMIN(id) que decide el orden
Madrid1
Valencia2
Bilbao4
Sevilla5
Zaragoza10
A Coruña12

La columna auxiliar no tiene que aparecer en la salida para que la intención sea válida: aquí MIN(id) se calcula de forma inequívoca para cada ciudad.

3. Si necesitas deduplicar primero y ordenar después por una clave auxiliar, separa las etapas

Una subconsulta o CTE puede convertir el criterio auxiliar en una columna explícita durante la deduplicación y dejar que la consulta exterior decida qué mostrar:

Separar deduplicación y presentación
SELECT estado
FROM (
  SELECT DISTINCT
         estado,
         CASE estado
           WHEN 'pendiente' THEN 1
           WHEN 'enviado' THEN 2
           WHEN 'cancelado' THEN 3
           ELSE 4
         END AS prioridad
  FROM pedidos
) AS estados
ORDER BY prioridad, estado;

En este ejemplo, prioridad depende únicamente de estado, así que añadirla dentro de la deduplicación no crea duplicados nuevos. La consulta exterior devuelve solo estado.

La regla no es idéntica en todos los motores

MotorComportamiento relevanteQué hacer
PostgreSQLPermite ordenar por expresiones no seleccionadas en un SELECT normal, pero con SELECT DISTINCT puede exigir que la expresión de ORDER BY aparezca en la lista de salida.Haz explícita la clave de orden o separa las etapas.
MySQL 8.4Con ONLY_FULL_GROUP_BY habilitado —modo activado por defecto— rechaza combinaciones DISTINCT + ORDER BY que producirían un orden arbitrario porque la expresión de orden no está representada por la lista seleccionada.No desactives el modo para ocultar la ambigüedad; reescribe la consulta.
SQL ServerCuando hay SELECT DISTINCT, los nombres o alias usados por ORDER BY deben estar definidos en la lista de selección.Incluye una clave legítima o usa una consulta exterior.
SQLiteEn un SELECT simple permite expresiones arbitrarias en ORDER BY. La consulta problemática puede ejecutarse localmente aunque otros motores la rechacen.No uses esa permisividad como contrato portable; expresa la regla de orden.

Importante: que SQLite acepte SELECT DISTINCT ciudad ... ORDER BY id no demuestra que la consulta sea portable ni que la intención esté bien definida. Cuando el orden depende de una fila «representante», define cómo elegirla.

Método de diagnóstico

  1. Confirma que el error apareció al combinar DISTINCT y ORDER BY.
  2. Marca qué expresiones forman realmente la identidad única que quieres devolver.
  3. Comprueba si cada expresión de ORDER BY tiene un único valor para esa identidad.
  4. Si no lo tiene, decide una regla: mínimo, máximo, fecha más reciente, prioridad calculada u otra medida explícita.
  5. Evita añadir una clave única al SELECT DISTINCT si eso destruye la deduplicación.
  6. Prueba la consulta final en el motor objetivo y verifica que el orden expresa la pregunta de negocio.

Práctica correctiva

Intermedia · DISTINCT, GROUP BY y ORDER BY

Ordena ciudades únicas por su primer id

Devuelve una sola fila por ciudad de la tabla clientes. Ordena las ciudades por el menor id asociado a cada una, pero no muestres el identificador en el resultado.

Criterio de éxito: la salida contiene solo ciudad, no destruyes la deduplicación y la regla que decide el orden es explícita.

Qué debes recordar

  • DISTINCT elimina duplicados según las expresiones seleccionadas.
  • Una columna oculta de ORDER BY puede tener varios valores para una misma fila deduplicada.
  • Añadir esa columna al SELECT DISTINCT puede cambiar la identidad del resultado y reintroducir filas.
  • Si el orden depende de una propiedad del grupo, define esa propiedad con una agregación o una etapa intermedia.
  • Las reglas exactas cambian entre motores; SQLite es más permisivo en un SELECT simple que PostgreSQL, SQL Server o MySQL en este caso.

Conceptos relacionados

Fuentes técnicas

La interacción entre deduplicación y ordenación se contrastó con documentación primaria de cada motor: