Volver a la lista de artículos Artículos
Lectura de 18 minutos

6 Ejemplos Útiles de CTEs en SQL Server

¿Cómo puedes utilizar las CTEs en SQL Server en tu día a día como profesional de los datos? Responderemos a esta pregunta dándote seis ejemplos.

CTE es la abreviatura de Common Table Expression. Se trata de una característica relativamente nueva de SQL Server que se puso a disposición con SQL Server 2005.

Una CTE es un resultado temporal con nombre. Este resultado sólo está disponible para la consulta que lo ejecuta. No se almacena, por lo que no ocupa espacio en disco. Una CTE es similar a una tabla temporal y puede utilizarse como cualquier otra tabla. Las CTEs se utilizan más a menudo con una sentencia SELECT, pero también se pueden utilizar con INSERT, UPDATE, y DELETE.

Las CTEs son uno de los conceptos más desafiantes en SQL Server. Para aprovechar sus beneficios, su aprendizaje debe ser cuidadosamente estructurado y no apresurado. Nuestro curso Consultas recursivas y expresiones de tabla comunes en MS SQL Server le mostrará cómo escribir una CTE sencilla en SQL Server para empezar. Después aprenderá a escribir múltiples CTEs, anidarlos y utilizarlos dentro de las sentencias SELECT, INSERT, UPDATE, y DELETE. Por último, aprenderá sobre estructuras de datos jerárquicas y gráficas y cómo utilizar CTEs recursivas en SQL Server para consultar dichos datos. Para asegurarte de que practicas lo suficiente, hay 112 ejercicios interactivos para completar en el curso.

Existen, por supuesto, otras formas de aprender CTEs que también puedes consultar.

Sintaxis CTE en SQL Server

Generalmente, la sintaxis CTE en SQL Server es como la del siguiente ejemplo:

WITH cte AS (  
  SELECT
    ...
)

SELECT
  ...
FROM cte;

Las CTEs siempre deben comenzar con la palabra clave WITH. A continuación viene el nombre de la CTE, la palabra clave AS y los paréntesis. En esos paréntesis se define la CTE. Definirla, como verás en nuestros ejemplos, significa escribir la sentencia SELECT. Puedes encontrar más detalles en este artículo que explica qué es una CTE.

6 Ejemplos de CTEs en SQL Server

1: Encontrar el Promedio de los Números Más Altos y Más Bajos de los Flujos Diarios

En los primeros cinco ejemplos, utilizaremos el mismo conjunto de datos. Muestra algunos datos inventados de una plataforma imaginaria de streaming de música; llamémosla Terpsícore.

El conjunto de datos consta de tres tablas. La primera es artisty aquí está la consulta para crear la tabla. Esta tabla contiene las siguientes columnas:

  • id - El ID del artista y la clave principal de la tabla.
  • artist_name - El nombre del artista.
idartist_name
1Prince
2Jimi Hendrix
3Santana

Esta tabla muestra tres artistas.

La siguiente tabla es albums. Aquí está la consulta para crearla. Y aquí están las columnas que contiene:

  • id - El ID del álbum y la clave primaria de la tabla.
  • artist_id - El artista (y la clave externa de la tabla).
  • album_title - El título del álbum.
  • year_released - El año de publicación del álbum.
idartist_idalbum_titleyear_released
12Are You Experienced1967
22Axis: Bold as Love1967
31Dirty Mind1980
42Electric Ladyland1968
53Abraxas1970
6119991982
73Santana III1971
83Santana1969
91Prince1979
101Controversy1981

Hay diez álbumes en la tabla.

La última tabla es streams. Muestra los datos de streaming de las canciones individuales. Puedes crear la tabla utilizando esta consulta. Y las columnas:

  • id - El ID del stream y la clave primaria de la tabla.
  • artist_id - El ID del artista y una clave externa.
  • album_id - El ID del álbum y una clave externa.
  • song_title - El nombre de la canción.
  • date - La fecha del stream.
  • number_of_streams - El número de veces que se reprodujo la canción en una fecha determinada.
  • pay_per_stream - Valor (en dólares) que Terpsichore paga a los artistas por cada emisión.
idartist_idalbum_idsong_titledatenumber_of_streamspay_per_stream
119I Wanna Be Your Lover2023-01-015970.013
216Little Red Corvette2023-01-014970.013
316D.M.S.R.2023-01-012170.013
413Uptown2023-01-0197480.013
513Do It All Night2023-01-012080.013

Hay 45 filas en esta tabla. Te mostraremos sólo las cinco primeras, para que te hagas una idea de la lógica de la tabla.

Ahora, ¡el ejemplo! Empecemos escribiendo sólo un CTE en SQL Server. Lo haremos para calcular el número medio más alto y más bajo de flujos diarios.

Aquí está el código; lo explicaremos a continuación:

WITH daily_streaming AS (
  SELECT date,
	   MIN(number_of_streams) AS minimum_streaming,
	   MAX(number_of_streams) AS maximum_streaming
  FROM streams
  GROUP BY date
)

SELECT AVG(minimum_streaming) AS average_minimum_daily_streaming,
	 AVG(maximum_streaming) AS average_maximum__daily_streaming
FROM daily_streaming;

Una CTE es brillante para descomponer la lógica de cualquier cálculo en SQL Server.

Recuerde que en un día se transmiten varias canciones. El propósito de nuestra CTE es obtener el número más bajo y más alto de streams cada día.

Como se mencionó anteriormente, un CTE en SQL Server siempre comienza con la palabra clave WITH, que es seguida por el nombre del CTE. Nuestro CTE se llama daily_streaming.

Después de la palabra clave AS viene el paréntesis con una sentencia SELECT - es decir, la definición del CTE. La utilizamos, junto con las funciones agregadas MIN() y MAX(), para calcular el mayor y menor número de flujos por fecha.

La siguiente sentencia SELECT utiliza los datos de la CTE, haciendo referencia a ella en la cláusula FROM. Como hemos dicho, una CTE se puede utilizar como cualquier otra tabla. En esta SELECT, usamos la función de agregado AVG() para obtener el promedio de los puntos máximos y mínimos de los flujos diarios.

La salida muestra que el promedio del punto más bajo es de 90 flujos. La media de los flujos diarios más altos es de 8.367.

average_minimum_daily_streamingaverage_maximum__daily_streaming
908,367

2: Calcular la tarifa media total pagada por canción

Ahora vamos a practicar lo que hemos aprendido. Nuevamente escribiremos un solo CTE.

El problema que hay que resolver es hallar la tarifa total media que Terpsícore pagó por cada canción.

He aquí la solución:

WITH paid_per_song AS (
  SELECT song_title,
	   SUM(number_of_streams * pay_per_stream) AS total_pay
  FROM streams
  GROUP BY id, song_title, pay_per_stream
)

SELECT song_title,
       AVG(total_pay) AS average_total_pay
FROM paid_per_song
GROUP BY song_title
ORDER BY average_total_pay DESC;

Usamos la CTE de SQL Server para calcular la tarifa total pagada por canción multiplicando el número de streams por el pago por stream, y luego sumándolo usando la función agregada SUM().

No hay cambios en cuanto a la sintaxis de la CTE: primero viene WITH, luego el nombre de la CTE, y AS viene después.

A continuación utilizamos un SELECT que invoca al CTE para calcular el pago medio por canción. Es sencillo: utilice AVG(), haga referencia a la CTE en FROM y agrupe por el título de la canción.

La consulta devuelve el siguiente resultado:

song_titleaverage_total_pay
Uptown47.4803330
I Wanna Be Your Lover36.8203330
Little Red Corvette33.8693330
The Wind Cries Mary23.6138660
Do It All Night12.4063330
If 6 Was 97.7824000
Samba Pa Ti7.5735000
All Along the Watchtower5.2032000
Bold as Love4.7424000
Burning of the Midnight Lamp3.7333330
D.M.S.R.3.1633330
Taboo2.4871000
Jingo2.1604000
Everything's Coming Our Way1.5466000
Incident at Neshabur0.9207000

Vemos que la canción 'Uptown' ganó 47,4803330 $ en total. La segunda y tercera canción por ingresos son "I Wanna Be Your Lover" y "Little Red Corvette". Si eres fan de este artista, no necesitas SQL para averiguar quién escribió estas tres canciones.

3: Encuentra el álbum más reproducido de cada artista

En este ejercicio, tienes que encontrar el álbum más reproducido de cada artista. Introduce el nombre del artista, el título del álbum y el número de streams por álbum.

Una vez más, se trata de una consulta con un solo CTE. Sin embargo, es un poco más compleja que las dos anteriores - hay algunos JOINs y una función ventana.

WITH album_streaming AS (
  SELECT artist_id,
	   album_id,
	   SUM(number_of_streams) AS streams_by_album,
	   RANK() OVER (PARTITION BY artist_id ORDER BY SUM(number_of_streams) DESC) AS streaming_rank
  FROM streams
  GROUP BY artist_id, album_id
)

SELECT artist_name,
       album_title,
	 streams_by_album
FROM album_streaming alst
JOIN albums al
ON alst.album_id = al.id
JOIN artist ar 
ON al.artist_id = ar.id
WHERE streaming_rank = 1;

De nuevo, la sintaxis CTE en SQL Server es familiar. Así que centrémonos en lo que hace esta CTE. La utilizamos para clasificar los álbumes por artista. En primer lugar, seleccionamos los ID de artista y álbum. A continuación, utilizamos SUM() para calcular el número de streams por álbum.

Ahora viene la parte crucial: clasificar la salida utilizando la función de ventana RANK(). Una vez invocada la función, aparece la cláusula OVER(), obligatoria para las funciones de ventana de SQL. Particionamos el conjunto de datos por el ID del artista y ordenamos los datos dentro de cada partición por el número de streams, en orden descendente.

¿Qué significa esto en la práctica? Significa que la función de ventana clasificará los álbumes de un artista, luego la clasificación se reinicia cuando la función llega al siguiente artista, y así sucesivamente. El álbum del artista con más streams se clasificará en primer lugar en su partición.

Si ejecuta sólo esta sentencia SELECT dentro del CTE, obtendrá este resultado:

artist_idalbum_idstreams_by_albumstreaming_rank
1313,8201
168,5462
198,4973
257,7221
273,6672
281,9643
3111,0691
325,8712
344,1893

Como puedes ver, los álbumes del primer artista se ordenan del primero al tercero, según el número de streams. Cuando llegamos al segundo artista, la clasificación se reinicia. Lo mismo ocurre con el tercer artista.

Veamos ahora qué hace la segunda sentencia SELECT. En realidad, no es nada complicado. Devuelve el nombre del artista y del álbum y el número de streams. Lo que complica esta consulta es que tenemos que unir tres tablas.

La primera unión es el CTE album_streaming. Luego la unimos con albums y luego con la tabla artist tabla. Al final, filtramos los datos utilizando la cláusula WHERE porque sólo nos interesa el álbum más reproducido.

Obtendrás este resultado:

artist_namealbum_titlestreams_by_album
PrinceDirty Mind13,820
Jimi HendrixAre You Experienced11,069
SantanaAbraxas7,722

El álbum de Prince con más streams es "Dirty Mind", con 13.820 streams. Para Jimi Hendrix, el álbum con más streams es 'Are You Experienced', y para Santana, es 'Abraxas'.

Esta solución utiliza las funciones de ventana, así que aquí tienes un recordatorio de cómo funcionan a la hora de clasificar datos.

4: Calcular la media de streams por canción y compararla con la media de streams por fecha

Ahora las cosas se complican. Pero no demasiado, no te preocupes. Nos estamos basando en lo que hemos aprendido hasta ahora sobre CTEs en SQL Server.

Aquí, necesitamos encontrar el número medio de streams por canción. A continuación, tenemos que calcular el número medio de streams por fecha.

La salida debe mostrar ambas métricas. Además, debe mostrar la diferencia entre la media de transmisiones por canción y la media diaria (como diferencia porcentual), el título de la canción y las fechas.

Hasta ahora, hemos escrito consultas con un CTE. Esta vez, la solución consiste en dos CTE. Veamos cómo funciona:

WITH streams_per_song AS (
  SELECT song_title,
	   AVG(number_of_streams) AS average_streams_per_song
  FROM streams
  GROUP BY song_title
),

streams_per_date AS (
  SELECT date,
	   AVG(number_of_streams) AS average_streams_per_date
  FROM streams
  GROUP BY date
)

SELECT song_title,
	 average_streams_per_song,
	 date,
	 average_streams_per_date,
	 (average_streams_per_song - average_streams_per_date)/CAST(average_streams_per_date AS DECIMAL(10,2))*100 AS diff_from_daily_average
FROM streams_per_song, streams_per_date;

El primer CTE se escribe como de costumbre. Lo utilizamos para calcular el número medio de streams por canción con AVG().

Después de cerrar los paréntesis, hay que separar el primer CTE del segundo CTE con una coma.

A continuación escribimos el segundo CTE. ¡He aquí! ¡No hay WITH! Así es. Cuando se escriben varios CTEs en una consulta en SQL Server, se escribe WITH sólo delante del primer CTE. El segundo (y cualquier CTE subsiguiente) comienza con el nombre del CTE; todo lo demás es igual.

Esta segunda consulta sirve para calcular el número medio de flujos por fecha. De nuevo, utilizamos la función AVG().

El tercer SELECT utiliza los datos de ambos CTEs. Devuelve todas las columnas necesarias. La última columna es diff_from_daily_average. La calculamos restando la media de flujos por fecha de la media de flujos por canción. La diferencia se divide por el promedio de streams por fecha y se multiplica por 100 para obtener el porcentaje. Además, convertimos el resultado en un tipo de datos decimal utilizando la función CAST().

Debido al tamaño de la salida, sólo mostraremos las primeras filas:

song_titleaverage_streams_per_songdateaverage_streams_per_datediff_from_daily_average
All Along the Watchtower8132023-01-011,031-21.14
Bold as Love7412023-01-011,031-28.13
Burning of the Midnight Lamp5832023-01-011,031-43.45
D.M.S.R.2432023-01-011,031-76.43
Do It All Night9542023-01-011,031-7.47

Los datos muestran que el flujo diario medio para el 1 de enero de 2023 es de 1.031. "All Along the Watchtower" está un 21,14% por debajo de esa media. Las dos canciones siguientes están un 28,13% y un 43,45% por debajo de la media diaria, y así sucesivamente.

5: Calcular la media de pago por álbum más alta y más baja por artista

Vamos a explicar lo que queremos decir con esto. Primero queremos encontrar la media de pago por álbum y fecha. A continuación, tenemos que encontrar el valor más bajo y más alto de pago por álbum. Después, queremos agregar los datos por artista. Junto con su nombre, necesitamos mostrar el valor de la paga más baja que el artista obtuvo por un álbum. Necesitamos hacer lo mismo con el pago más alto por un álbum.

La solución en SQL Server contiene dos CTEs. Sin embargo, esta vez se trata de un CTE anidado. Es decir, el segundo CTE hace referencia al primer CTE. Veamos cómo funciona:

WITH pay_per_album AS (
  SELECT album_id,
	   date,
	   AVG(number_of_streams * pay_per_stream) AS average_pay_per_album
  FROM streams
  GROUP BY album_id, date
),
	
min_max_average_pay AS (
  SELECT album_id,
	   MIN(average_pay_per_album) AS lowest_average_pay_by_album,
	   MAX(average_pay_per_album) AS highest_average_pay_by_album
  FROM pay_per_album
  GROUP BY album_id
)

SELECT artist_name,
	 MIN(lowest_average_pay_by_album) AS lowest_album_pay_by_artist,
	 MAX(highest_average_pay_by_album) AS highest_album_pay_by_artist
FROM min_max_average_pay mmap
JOIN albums al
ON mmap.album_id = al.id
JOIN artist ar
ON al.artist_id = ar.id
GROUP BY artist_name;

¡Ten cuidado cuando leas la explicación del código! Es fácil perderse en todas estas agregaciones. Para facilitar la lectura, he copiado cada parte de la consulta y la he seguido con una explicación. Empezaremos con el primer CTE:

WITH pay_per_album AS (
  SELECT album_id,
	   date,
	   AVG(number_of_streams * pay_per_stream) AS average_pay_per_album
  FROM streams
  GROUP BY album_id, date
),

El primer CTE calcula el pago medio por álbum y la fecha. Esto se hace multiplicando el número de streams por el pago por stream y usando AVG().

min_max_average_pay AS (
  SELECT album_id,
	   MIN(average_pay_per_album) AS lowest_average_pay_by_album,
	   MAX(average_pay_per_album) AS highest_average_pay_by_album
  FROM pay_per_album
  GROUP BY album_id
)

Al escribir el segundo CTE en SQL Server, la sintaxis es la misma que en el ejemplo anterior - sin WITH adicional, comienza con el nombre del CTE y separa los CTEs con una coma. La única diferencia es que esta vez el segundo CTE hace referencia al primer CTE, no al conjunto de datos original.

Este CTE anidado utiliza las funciones MIN() y MAX() para encontrar el salario medio más bajo y más alto de cada álbum para todas las fechas. El primer CTE está referenciado en FROM.

SELECT artist_name,
	 MIN(lowest_average_pay_by_album) AS lowest_album_pay_by_artist,
	 MAX(highest_average_pay_by_album) AS highest_album_pay_by_artist
FROM min_max_average_pay mmap
JOIN albums al
ON mmap.album_id = al.id
JOIN artist ar
ON al.artist_id = ar.id
GROUP BY artist_name;

Por último, SELECT une el segundo CTE con las funciones albums y artist tablas. Volvemos a aplicar las funciones MIN() y MAX() sobre el resultado del segundo CTE. Esto es para devolver sólo los valores del menor y mayor pago de todos los álbumes de cada artista.

Esto es lo que obtenemos después de ejecutar la consulta:

artist_namelowest_album_pay_by_artisthighest_album_pay_by_artist
Jimi Hendrix1.5963.19
Prince4.6497.31
Santana0.9110.22

6: Encontrar el camino más largo entre Rotterdam y Amsterdam

Se trata de una variación del problema del camino más corto de la teoría de grafos, con la diferencia de que buscaremos el camino más largo.

Un grafo es un tipo de estructura de datos formada por nodos o puntos conectados por aristas. Al estar conectados, es posible encontrar un camino de un nodo a otro aunque no estén conectados directamente.

Piénsalo como un mapa de carreteras. Este es exactamente el ejemplo que utilizaremos aquí. A continuación se muestra la tabla cities_distanceque muestra las ciudades y la distancia entre ellas. Utilice esta consulta para crear la tabla. Contiene estas columnas:

  • ciudad_de - La ciudad de origen.
  • city_to - La ciudad de llegada.
  • distance - La distancia entre las dos ciudades, en kilómetros.

Estos son los datos:

city_fromcity_todistance
RotterdamAmsterdam78.20
RotterdamGouda24.10
AmsterdamGouda72.50
GoudaLeiden34.10
AmsterdamLeiden50.00
RotterdamLeiden35.40
GoudaUtrecht44.00
UtrechtAmsterdam52.40
LeidenGouda34.10

Necesitamos encontrar el camino más largo de Rotterdam a Amsterdam. El camino debe incluir el nombre de todas las ciudades a lo largo del camino, separadas por '/'. Además, debemos mostrar la longitud del camino más largo.

Cuando decimos el camino más largo, queremos excluir los caminos circulares (en los que se pueden hacer rondas interminables y aumentar la distancia). Queremos que el camino más largo sólo pase una vez por cada ciudad.

Para resolver este problema, utilizaremos una CTE recursiva. Es una consulta que se referencia a sí misma hasta llegar al final de los datos. Esta característica es ideal para consultar datos de grafos, donde múltiples caminos pueden llevar al mismo objetivo.

Veamos cómo funciona esta ETC recursiva:

WITH longest_path AS (
  SELECT cd.city_to,
         CAST((cd.city_from + '/' + cd.city_to) AS VARCHAR(100)) AS path,
        cd.distance AS distance
   FROM cities_distance cd
   WHERE cd.city_from = 'Rotterdam'

UNION ALL

  SELECT cd.city_to,
         CAST((lp.path + '/' + cd.city_to) AS VARCHAR(100)) AS path,
         CAST((lp.distance + cd.distance) AS DECIMAL(10,2))
  FROM longest_path lp 
  INNER JOIN cities_distance cd
  ON cd.city_from = lp.city_to
  WHERE lp.city_to <> 'Amsterdam'
  AND lp.path NOT LIKE '%/' + cd.city_to + '/%'
)

SELECT TOP 1 lp.path,
	 lp.distance
FROM longest_path lp
WHERE lp.city_to = 'Amsterdam'
ORDER BY lp.distance DESC;

La sintaxis es la misma que antes - la consulta recursiva también empieza por WITH en SQL Server.

Como siempre, hay una sentencia SELECT entre paréntesis. Hay dos, para ser más precisos. Veamos qué hace la primera.

WITH longest_path AS (
  SELECT cd.city_to,
         CAST((cd.city_from + '/' + cd.city_to) AS VARCHAR(100)) AS path,
         cd.distance AS distance
  FROM cities_distance cd
  WHERE cd.city_from = 'Rotterdam'

El primer SELECT en recursividad se llama miembro ancla. Sirve para seleccionar el punto de partida de la recursión. El punto de partida será Rotterdam, que obtenemos filtrando esta ciudad en WHERE. La columna city_to se utiliza para mostrar todos los destinos finales a los que se puede llegar directamente desde Rotterdam. La columna path mostrará todas las ciudades de origen y destino. La longitud de esa ruta se muestra en la columna distance.

A continuación viene UNION ALL, que unirá los resultados del ancla y el miembro recursivo, es decir, el segundo SELECT. La unión de estas dos consultas es necesaria para que la recursión funcione.

Nota: En algunos otros dialectos de SQL, también es posible utilizar UNION. Sin embargo, SQL Server sólo permite UNION ALL.

Ahora llegamos al miembro recursivo. Hace referencia al propio CTE en FROM y lo une con la tabla cities_distance. Para que las consultas estén unidas, ambas deben tener el mismo número de columnas del mismo tipo de datos. Las dos primeras columnas son las mismas que en el miembro ancla. La columna longest_path suma todas las distancias para llegar a todas las ciudades desde Rotterdam.

SELECT cd.city_to,
       CAST((lp.path + '/' + cd.city_to) AS VARCHAR(100)) AS path,
       CAST((lp.distance + cd.distance) AS DECIMAL(10,2))
FROM longest_path lp 
INNER JOIN cities_distance cd
ON cd.city_from = lp.city_to
WHERE lp.city_to <> 'Amsterdam'
AND lp.path NOT LIKE '%/' + cd.city_to + '/%'
)

También hemos añadido dos condiciones en WHERE. La primera excluye todas las relaciones en las que Ámsterdam es el destino final; buscamos el camino más largo, no el más corto, hasta Ámsterdam. La segunda condición garantiza que cualquier ciudad nueva que se añada al camino no esté ya incluida en él. De lo contrario, la consulta entrará en una recursión interminable. Esto responde a lo que hemos dicho antes: el camino más largo no debe visitar la misma ciudad más de una vez.

Para entender mejor de qué estamos hablando, aquí está la salida de la CTE recursiva:

city_topathdistance
AmsterdamRotterdam/Amsterdam78.20
GoudaRotterdam/Gouda24.10
LeidenRotterdam/Leiden35.40
GoudaRotterdam/Leiden/Gouda69.50
UtrechtRotterdam/Leiden/Gouda/Utrecht113.50
AmsterdamRotterdam/Leiden/Gouda/Utrecht/Amsterdam165.90
LeidenRotterdam/Gouda/Leiden58.2
UtrechtRotterdam/Gouda/Utrecht68.1
AmsterdamRotterdam/Gouda/Utrecht/Amsterdam120.5

Se puede ver que hay tres caminos de Rotterdam a Amsterdam. Uno es directo, con una distancia de 78,20 km. El segundo y el tercero pasan por otras ciudades y tardan 165,90 y 120,50 km, respectivamente.

Eso sí, ¡este no es el resultado final! Nuestra solución también tiene una sentencia SELECT que hace referencia al CTE:

SELECT TOP 1 lp.path,
	 lp.distance
FROM longest_path lp
WHERE lp.city_to = 'Amsterdam'
ORDER BY lp.distance DESC;

Este SELECT devuelve el trayecto y la distancia. Utilizamos el comando TOP 1 combinado con ORDER BY para devolver el camino más largo de Rotterdam a Amsterdam. Ordenamos los datos de mayor a menor distancia, por lo que la primera fila será también el camino más largo.

He aquí el resultado final:

pathdistance
Rotterdam/Leiden/Gouda/Utrecht/Amsterdam165.90

Este resultado muestra que el camino más largo de Rotterdam a Amsterdam es de 165,9 km y pasa por Leiden, Gouda y Utrecht.

Si no se cansa de hablar de este tema, aquí tiene más ejemplos de CTE.

¿Cuándo utilizar las CTE?

Como ha visto en nuestros ejemplos, una CTE tiene muchos propósitos en SQL Server.

Uno de ellos es que generalmente mejora la legibilidad del código. Todas las soluciones anteriores (excepto la recursión) podrían haberse escrito con subconsultas. Pero eso haría el código mucho más largo y menos claro.

Si lo piensas bien, las subconsultas suelen escribirse en contra de la lógica del problema que intentas resolver. Primero tienes la consulta principal, que utiliza la salida de la subconsulta. Así que la subconsulta suele ser el primer paso del cálculo, aunque no esté colocada así en el código.

En cambio, los CTE pueden escribirse siguiendo la lógica del problema. Puede escribir varios CTEs separados y combinar sus salidas en las sentencias SELECT. También puede hacer referencia a la salida de un CTE con la segunda consulta (o tercera, cuarta...), siendo la sentencia final SELECT otro nivel de cálculo.

Uno de los ejemplos también mostraba que se podían clasificar datos en SQL Server utilizando una función de ventana y una CTE.

Y si quieres escribir consultas recursivas en SQL Server, no puedes hacerlo sin CTEs. Un CTE puede ser no recursivo, pero no existen consultas recursivas sin CTE. Junto con los gráficos, la recursividad es extremadamente útil en la consulta de estructuras jerárquicas, como la organización de datos y los árboles genealógicos.

Puedes encontrar más información sobre cuándo utilizar una CTE aquí.

¡Los CTEs son la puerta de entrada al uso de SQL avanzado!

Los CTEs son uno de los conceptos más avanzados de SQL Server. Si quieres abrir la puerta a habilidades de nivel avanzado en SQL Server, los CTEs son imprescindibles.

A medida que tus consultas en SQL Server se vuelvan más complejas, pronto te darás cuenta de que aprender CTEs fue una de las mejores decisiones que tomaste. También son un trampolín para las consultas recursivas, que permiten consultar tipos inusuales de estructuras de datos en SQL Server, como jerarquías y gráficos.

Este artículo es sólo un avance de los conocimientos que puedes encontrar en el curso Consultas recursivas y expresiones de tabla comunes en MS SQL Server. Así que no se detenga aquí. Hay mucho más que aprender.