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:
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.
| id | ciudad |
|---|---|
| 1 | Madrid |
| 3 | Madrid |
| 6 | Madrid |
| 9 | Madrid |
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
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
SELECT DISTINCT ciudad
FROM clientes
ORDER BY ciudad;| 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:
SELECT ciudad
FROM clientes
GROUP BY ciudad
ORDER BY MIN(id), ciudad;| ciudad | MIN(id) que decide el orden |
|---|---|
| Madrid | 1 |
| Valencia | 2 |
| Bilbao | 4 |
| Sevilla | 5 |
| Zaragoza | 10 |
| A Coruña | 12 |
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:
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
| Motor | Comportamiento relevante | Qué hacer |
|---|---|---|
| PostgreSQL | Permite 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.4 | Con 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 Server | Cuando 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. |
| SQLite | En 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
- Confirma que el error apareció al combinar
DISTINCTyORDER BY. - Marca qué expresiones forman realmente la identidad única que quieres devolver.
- Comprueba si cada expresión de
ORDER BYtiene un único valor para esa identidad. - Si no lo tiene, decide una regla: mínimo, máximo, fecha más reciente, prioridad calculada u otra medida explícita.
- Evita añadir una clave única al
SELECT DISTINCTsi eso destruye la deduplicación. - Prueba la consulta final en el motor objetivo y verifica que el orden expresa la pregunta de negocio.
Práctica correctiva
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.
DISTINCT ciudad, id no sirve porque id vuelve diferentes las filas.ciudad para obtener una fila por ciudad.MIN(id) únicamente como criterio de ORDER BY.Solución razonada
SELECT ciudad
FROM clientes
GROUP BY ciudad
ORDER BY MIN(id), ciudad;La comprobación local devuelve, en este orden: Madrid, Valencia, Bilbao, Sevilla, Zaragoza y A Coruña. GROUP BY ciudad define una fila por ciudad; MIN(id) aporta una clave inequívoca para ordenar cada grupo sin aparecer en la salida.
Qué debes recordar
DISTINCTelimina duplicados según las expresiones seleccionadas.- Una columna oculta de
ORDER BYpuede tener varios valores para una misma fila deduplicada. - Añadir esa columna al
SELECT DISTINCTpuede 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
SELECTsimple 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: