ORDER BY en SQL Server, la parte confusa.

Imagen principal del árticulo

Probablemente una de los aspectos más confusos en T-SQL es entender cuando el resultado de una consulta se devuelve en un orden particular o cuando no. Para este artículo utilizaremos la base de datos de Microsoft, Northwind.

Consideremos en la siguiente consulta:

¿Existe una garantía de que las filas van a ser devueltas en un orden particular, y si es así, cual es ese orden?

Algunos hacen una suposición intuitiva de que las filas serán retornadas en el orden de inserción; algunos asumen que en el orden del Primary Key; otros saben que no hay ningún tipo de orden garantizado.

Por ejemplo, en la consulta realizada nos da el siguiente resultado cuando se corre en SQL Server:

Nortwind1

Puede parecer que el resultado está ordenado por EmployeeID, pero eso no está garantizado. Puede ser mas confuso si corres la misma consulta varias veces, puede parecer que el resultado siga siendo devuelto en el mismo orden, pero de nuevo, eso no está garantizado. Cuando el motor de base de datos (SQL Server en este caso) procesa esta consulta, sabe que puede retornar los datos en cualquier orden porque no hay una instrucción explicita para devolver los datos en un orden especifico. Podría ser que, debido a la optimización y otras razones, el motor de base de datos de SQL Server decidió procesar los datos de una manera particular en esta ocasión.

En resumen: una consulta que no tiene una instrucción explicita para retornar las filas en un orden particular no garantiza el orden de las filas en el resultado. Cuando necesitar garantizar un orden, la única manera de hacerlo es añadiendo la clausula ORDER BY a la consulta.

Usando la clausula ORDER BY para ordenar datos

La única manera de garantizar realmente que el orden de las filas retornadas desde una consulta en un orden especifico y agregando la clausula ORDER BY.

Por ejemplo, si quieres retornar información acerca de los empleados del estado de Washington en Estados Unidos, ordenados por ciudad, especifica en la columna city la clausula ORDER BY de la siguiente manera:

El resultado de la consulta:

Nortwind2

Si no se especifica una dirección para el ordenamiento, el orden ascendiente es asumido por defecto. Puedes especificar el orden ascendiente de manera explícita como city ASC. Para el orden descendiente debes espeficar DESC, de la siguiente manera:

Este es el resultado:

Nortwind3

La columna city no es única con el filtro del país y la región, y por lo tanto, el orden de las filas con la misma ciudad (en este caso, Seattle) no está garantizado, o sea, entre esas dos filas no hay un orden especifico. Afortunadamente, se puede especificar una lista de columnas para ordenar separadas por coma. Por ejemplo, podemos indicar la columna EmployeeID como la segunda columna para ordenar de la siguiente manera:

Este es el resultado:

Nortwind4

Ahora, la lista es única siempre y cuanto el contenido no cambie, el resultado esta garantizado a ser repetible en ese orden.  También se puede indicar el orden de dirección por cada columna, por ejemplo: ORDER BY columna1 DESC, columna2, columna3 DESC (la columna1 descendente, la columna2 ascendente y la columna 3 descendente).

También se puede ordenar el resultado por un campo que no este listado en la clausula SELECT, por ejemplo:

El resultado es el siguiente:

Nortwind5

Si se fijan, estamos ordenando por el campo BirthDate y este no está listado en el resultado, aunque obviamente haría más sentido que este esté listado. La regla es que puede ordenar las filas de resultado por elementos que no forman parte de la lista SELECT. Esta regla cambia cuando también se especifica la cláusula DISTINCT y por una buena razón. Cuando se utiliza DISTINCT, se eliminan los duplicados; entonces las filas de resultados no necesariamente se asignan a las filas de origen de una manera uno a uno, en lugar de uno a muchos. Por ejemplo, pensemos por qué la siguiente consulta es inválida:

Puede tener varios empleados -cada uno con una fecha de nacimiento diferente- de la misma ciudad. Pero solo estamos regresando una fila para cada ciudad distinta en el resultado. Así que, dada una ciudad (digamos, Seattle) con varios empleados, ¿cuál de las fechas de nacimiento de los empleados debería aplicarse como el valor de orden? La consulta no sólo seleccionará uno; más bien, simplemente falla. Por lo tanto, en caso de que se use la cláusula DISTINCT, estamos limitados en la lista ORDER BY sólo a los elementos que aparecen en la lista SELECT, como en la siguiente consulta.

Ahora la consulta es perfectamente razonable, devolviendo el siguiente resultado:

Norwind6DISTINCT

Otro aspecto difícil de ordenar es el tratamiento de NULLs. En SQL Server se ordenan antes de no-NULL (cuando se utiliza una dirección ascendente). Como ejemplo, la siguiente consulta devuelve para cada pedido el ID de pedido y la fecha enviada, ordenados por este último.

Este es parte del resultado:

Nortwind7

Es importante tener estas consideraciones en cuenta al momento de trabajar con el ordenamiento de datos ya que podríamos no estar ofreciendo la información correcta.

[Referencia] Querying Microsoft Sql Server 2012