DISTINCT, TOP y ORDER BY: reducir y ordenar un resultado
Una consulta puede devolver todas las filas que cumplen una condición y aun así no responder exactamente lo que buscamos. Quizá necesitamos conocer los estados existentes sin repetirlos, revisar solo los pedidos más recientes o presentar los precios de menor a mayor.
La idea
Estas tres construcciones afectan el resultado de formas distintas: DISTINCT elimina repeticiones, TOP limita la cantidad de filas y ORDER BY establece su orden.
Sintaxis
SELECT [DISTINCT] [TOP (cantidad)]
Columna1,
Columna2
FROM dbo.Tabla
ORDER BY
Columna1 [ASC | DESC];
Los elementos entre corchetes son opcionales en esta representación. Los corchetes ayudan a leer la forma general; no deben copiarse literalmente al escribir la consulta.
ORDER BY: declarar el orden
Las tablas no tienen un orden de lectura que debamos asumir. Aunque una consulta parezca devolver siempre las filas de la misma manera, ese comportamiento puede cambiar con el plan, los índices o la ejecución.
SELECT
p.IdProducto,
p.Nombre,
p.Precio
FROM dbo.Producto AS p
ORDER BY
p.Precio DESC,
p.IdProducto ASC;
DESC ordena el precio de mayor a menor. Cuando dos productos tienen el mismo precio, IdProducto ASC proporciona un segundo criterio estable.
TOP: limitar la cantidad de filas
Para obtener los tres productos de mayor precio:
SELECT TOP (3)
p.IdProducto,
p.Nombre,
p.Precio
FROM dbo.Producto AS p
ORDER BY
p.Precio DESC,
p.IdProducto ASC;
| IdProducto | Nombre | Precio |
|---|---|---|
| 6 | Disco externo 1 TB | 1399.00 |
| 3 | Soporte para monitor | 799.00 |
| 4 | Teclado compacto | 629.90 |
TOP sin ORDER BY limita filas, pero no define cuáles son las primeras desde el punto de vista del negocio. Si pedimos “los tres más caros”, el orden forma parte de la pregunta.
También puede expresarse como porcentaje:
SELECT TOP (10) PERCENT
p.IdProducto,
p.Nombre,
p.Precio
FROM dbo.Producto AS p
ORDER BY p.Precio DESC;
En resultados pequeños, el redondeo puede producir una cantidad que no parece intuitiva. Para procesos que requieren un número exacto suele ser más claro utilizar una cantidad de filas.
DISTINCT: eliminar filas repetidas
Si solo queremos conocer los estados que aparecen en los pedidos:
SELECT DISTINCT
p.Estado
FROM dbo.Pedido AS p
ORDER BY p.Estado;
| Estado |
|---|
| Cancelado |
| Confirmado |
| Enviado |
| Pendiente |
DISTINCT considera juntas todas las expresiones seleccionadas. Si agregamos IdPedido, cada combinación de identificador y estado será diferente, aunque el estado se repita:
SELECT DISTINCT
p.IdPedido,
p.Estado
FROM dbo.Pedido AS p;
En ese caso, DISTINCT no reduce las filas porque IdPedido ya identifica cada pedido.
Qué conviene comprobar
DISTINCT puede ocultar una unión mal construida. Si aparecen duplicados después de agregar un JOIN, conviene revisar primero la cardinalidad de la relación y la condición escrita en ON.
Para resultados paginados, un orden estable necesita una columna, o combinación de columnas, que permita desempatar. Ordenar solo por fecha puede producir páginas inconsistentes cuando varias filas comparten el mismo valor.
TOP limita el resultado completo. Cuando necesitamos cierta cantidad de filas dentro de cada grupo, utilizamos funciones como ROW_NUMBER, RANK o DENSE_RANK con OVER.
Relacionado con
WHERE: limita las filas antes de ordenar el resultado.OFFSETyFETCH: permiten paginación.ROW_NUMBER,RANKyDENSE_RANK: clasifican dentro de una ventana.INNER JOIN: puede multiplicar filas cuando existen varias coincidencias.