El SQL que necesitarías es:
SELECT Course1_ID = MAX(CASE WHEN RowNum = 1 THEN ID END),
Course1_Name = MAX(CASE WHEN RowNum = 1 THEN Name END),
Course2_ID = MAX(CASE WHEN RowNum = 2 THEN ID END),
Course2_Name = MAX(CASE WHEN RowNum = 2 THEN Name END),
Course3_ID = MAX(CASE WHEN RowNum = 3 THEN ID END),
Course3_Name = MAX(CASE WHEN RowNum = 3 THEN Name END)
FROM ( SELECT ID,
Name,
RowNum = ROW_NUMBER() OVER(ORDER BY ID)
FROM Courses
) C;
Pero con contenido desconocido necesitarías generar esto dinámicamente:
DECLARE @SQL NVARCHAR(MAX) = 'SELECT ' +
STUFF(( SELECT ',Course' + RowNum + '_ID = MAX(CASE WHEN RowNum = ' + RowNum + ' THEN ID END)
,Course' + RowNum + '_Name = MAX(CASE WHEN RowNum = ' + RowNum + ' THEN Name END)'
FROM ( SELECT RowNum = CAST(ROW_NUMBER() OVER(ORDER BY ID) AS VARCHAR(10))
FROM Courses
) c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, '') +
' FROM ( SELECT ID,
Name,
RowNum = ROW_NUMBER() OVER(ORDER BY ID)
FROM Courses
) C;'
EXECUTE SP_EXECUTESQL @SQL;
Otra forma de lograr el mismo resultado es:
DECLARE @SQL NVARCHAR(MAX) = '';
SELECT @SQL = @SQL +
',Course' + RowNum + '_ID = MAX(CASE WHEN RowNum = ' + RowNum + ' THEN ID END)
,Course' + RowNum + '_Name = MAX(CASE WHEN RowNum = ' + RowNum + ' THEN Name END)'
FROM ( SELECT RowNum = CAST(ROW_NUMBER() OVER(ORDER BY ID) AS VARCHAR(10))
FROM Courses
) c;
SET @SQL = 'SELECT ' + STUFF(@SQL, 1, 1, '') + '
FROM ( SELECT ID,
Name,
RowNum = ROW_NUMBER() OVER(ORDER BY ID)
FROM Courses
) c;';
EXECUTE SP_EXECUTESQL @SQL;
Esto elimina las costosas extensiones XML para concatenar filas en columnas
Si el orden de los cursos es relevante, simplemente puede cambiar la cláusula order by en el ROW_NUMBER
función.