Los resultados (SELECT) que arroja las consultas SQL es, en la mayoría de los casos, en forma de listados de los campos procedentes de una o mas tablas, una vez aplicados los filtros (WHERE) que se necesitan para extraer datos concluyentes.
Pero, evidentemente, una vez que tenemos un listado, querremos ordenarlo de una determinada forma por orden alfabético en caso de alfanuméricos o por orden numérico, tanto ascendente como descendente.
La clausula ORDER BY se encarga de realizar esta labor, como veremos en los ejemplos que siguen.
Este post forma parte del Tutorial básico de SQL Server cuyo índice completo puedes ver aquí: Tutorial básico de SQL Server
En el post anterior vimos numerosos scripts de filtros sobre nuestra tabla Clientes. Por ejemplo practicamos con:
SELECT [Nombre]
,[Apellidos]
,[Edad]
,[Direccion]
,[Cuenta]
FROM [dbo].[Clientes]
WHERE Edad BETWEEN 30 AND 39
GO
Y el resultado (al menos en mi caso) fue este:

Se puede entonces ordenar por cualquiera de estas columnas de forma muy intuitiva añadiendo al final la clausula de ordenación y el campo por el que queremos hacerlo. Por ejemplo el nombre:
SELECT [Nombre]
,[Apellidos]
,[Edad]
,[Direccion]
,[Cuenta]
FROM [dbo].[Clientes]
WHERE Edad BETWEEN 30 AND 39
ORDER BY Nombre
GO

Se ha ordenado alfabéticamente por el campo 'Nombre' y de forma ascendente (de 'a' hasta 'z'). Esto es así porque es la opción por defecto. De hecho si se quiere indicar específicamente como aclaración tendríamos que indicar la palabra ASC. La opción descendente es DESC. Veámoslo con otro ejemplo
SELECT [Nombre]
,[Apellidos]
,[Edad]
,[Direccion]
,[Cuenta]
FROM [dbo].[Clientes]
WHERE Edad BETWEEN 30 AND 39
ORDER BY Apellidos DESC
GO

La ordenación también se puede hacer por varios campos. Supongamos que queremos listar todos los registros no nulos en su campo 'Cuenta', ordenados por edad, pero en caso de coincidencia en la misma, liste primero el que tiene cuenta. Se especifican los campos separados por comas.
SELECT [Nombre]
,[Apellidos]
,[Edad]
,[Direccion]
,[Cuenta]
FROM [dbo].[Clientes]
WHERE Cuenta is not null
ORDER BY Edad ASC, Cuenta DESC
GO

Vemos como hay tres parejas de clientes que coinciden en edad. En ese caso ordena primero el 1 de "tiene cuenta" y después el 0 (actúa el DESC). En el caso de que ambos sean 1 o ambos sean 0 la ordenación es interna o aleatoria (en este caso tendríamos la posibilidad de especificar un tercer campo de ordenación).
Github Copilot
Vamos a ayudarnos de la IA para ver un último ejemplo referente al campo 'Direccion' que parece un poco problemático:
Construye un script para seleccionar nombre, apellidos y dirección de la tabla Primera..Clientes y ordenandolos por Dirección, comenzando por las calles (Calle, C/, C/., cl) y despues por el resto

El resultado es aceptable, ha realizado lo que le hemos pedido. Pero lo que parecía una clausula fácil, se ha complicado en este ejemplo, además de que es mejorable. Vamos a analizarlo.
Según el comentario que ha insertado en el script nos ha interpretado bien, pero ha tenido que realizar un CASE en la clausula ORDER BY. Esto es perfectamente posible, al fin y al cabo realiza un primer grupo prioritario de posibles calles y le asigna un 0, el resto le asigna un 1. En la ordenacion ASC hace que primero se obtengan los 0 (las calles) y después los 1 (el resto).
El segundo criterio de ordenación dentro de cada grupo es la propia dirección ordenado alfabéticamente, correcto.
Sin embargo nos gustaría que los nombres de las calles fuese el criterio de ordenación ignorando la abreviatura "C/" o "Calle" que las precede. Probemos esto:
Mejora el anterior script: el primer grupo de calles necesito que esté ordenado por el nombre de la calle, independientemente si va precedido de "Calle" o "C/" o C/." etc.
Y efectivamente se puso a trabajar; en el proceso me indicaba esto (a tí te indicará algo distinto):

Estuvo 19 segundos, hablaba para alguien más "El usuario quiere.." (un poco mas y me llama pesado...), pero los ejemplos que muestra parece que lo estaba interpretando bien. Finalmente dice algo de manipulación de strings. Este ha sido mi caso:


La que ha armado. Ha tenido que recurrir a manipulación de strings o cadenas para atender lo solicitado. Está fuera del ámbito de este tutorial básico (Las funciones de manipulación de strings requerirán una serie de varios posts) pero es intuitivo:
La función REPLACE (de tres argumentos) sustituye en el campo indicado en el primer argumento, la 'Dirección' previamente pasada a minúsculas (LOWER como forma de unificación), lo que encuentre del segundo argumento (cada uno de los prefijos + espacio), por lo que indicamos en el tercero (nada ''), de forma que ya tenemos la ordenación por el nombre de la calle. En definitiva elimina "Calle", "C/", "Cl." etc. los sustituye por "".
Finalmente LTRIM es una función que engloba todo para eliminar espacios por la izquierda.
Por fin el listado está ahora ordenado a nuestra necesidad; por ejemplo la "Calle Imaginada" está en el lugar alfabético correcto.
Esto además es una muestra de como GitHub Copilot nos puede ayudar a aprender conceptos intuitivos como pueden ser estas funciones, a pesar de que en un principio los desconozcamos.
También recuerda que las propuestas de tu Copilot pueden ser diferentes a los ejemplos expuestos por mí. Si tienes algún problema puedes dejar un comentario e intentamos solucionarlo.
Este post de ordenación se ha ido hasta manipular cadenas mediante CASE, pero es lógico: en SQL todo está relacionado. ¡Mas aprendizaje en el próximo!