SQL преобразует строки, сгенерированные CTE, в столбцы, включая имена полей - PullRequest
0 голосов
/ 11 июля 2019

У меня есть CTE, который генерирует данные в переменное количество строк. Это почасовые значения, которые мне нужно использовать при соединении с другой таблицей, но эта часть здесь не важна.

Одна часть CTE выглядит так:

DECLARE @interval INT = 3 -- hours
DECLARE @period INT = 24 -- hours
;WITH cteHour AS (
    SELECT CAST('i0' AS VARCHAR(6)) AS fieldname, 0 AS i, 0 AS startpos
    UNION ALL
    SELECT CONCAT('i', CAST(i + 1 AS VARCHAR(5))) AS fieldname, i + 1 AS i, startpos + @interval AS startpos
    FROM cteHour
    WHERE (startpos + @interval) < @period
) SELECT fieldname, startpos FROM cteHour

И генерирует такие данные (в зависимости от значений @interval и @period):

fieldname startpos
--------- -----------
i0        0
i1        3
i2        6
i3        9
i4        12
i5        15
i6        18
i7        21

У меня вопрос, как я могу получить результаты в столбцы вместо строк, используя первый столбец в качестве имен полей, например:

i0 i1 i2 i3 i4 i5 i6 i7
-- -- -- -- -- -- -- --
0  3  6  9  12 15 18 21

Я предполагаю, что для этого потребуется PIVOT, но, насколько я знаю, поворот не может генерировать имена полей динамически. Так что я открыт для любых ответов, которые выполнили работу.

Ответы [ 3 ]

0 голосов
/ 11 июля 2019

Следующий запрос должен делать то, что вы хотите, он использует временную таблицу, но вы получите представление о том, как этот подход

DECLARE @interval INT = 3 -- hours
DECLARE @period INT = 24 -- hours
;WITH cteHour AS (
    SELECT CAST('i0' AS VARCHAR(6)) AS fieldname, 0 AS i, 0 AS startpos
    UNION ALL
    SELECT CONCAT('i', CAST(i + 1 AS VARCHAR(5))) AS fieldname, i + 1 AS i, startpos + @interval AS startpos
    FROM cteHour
    WHERE (startpos + @interval) < @period
)

SELECT * INTO #temp FROM cteHour;

DECLARE @pvt NVARCHAR(MAX) = '';

SET @pvt = STUFF(
  (SELECT DISTINCT N', ' + QUOTENAME([fieldname]) FROM #temp FOR XML PATH('')),1,2,N'')

EXEC (N'SELECT *
            FROM #temp
        PIVOT (MAX([startpos]) FOR [fieldname] IN('+@pvt+')) AS PIV');
0 голосов
/ 11 июля 2019

Вот самый простой ответ с использованием динамического запроса

DECLARE @interval INT = 3 -- hours
DECLARE @period INT = 24 -- hours
DECLARE @startpos INT = 0
DECLARE @i INT = 0
DECLARE @sql NVARCHAR(MAX) = 'SELECT '
WHILE @startpos < @period
BEGIN
    SET @sql = @sql + (CASE WHEN @i > 0 THEN ',' ELSE '' END) +
    CAST(@startpos AS VARCHAR(5)) + ' AS i' + CAST(@i AS VARCHAR(5))

    SET @i = @i + 1
    SET @startpos = @startpos + @interval
END
print @sql
exec sp_executesql @sql
0 голосов
/ 11 июля 2019

Поскольку требуется динамический sql, пропустите сводную часть и сразу же сгенерируйте динамический запрос из вашего cte

DECLARE @sql NVARCHAR(MAX)

SELECT  @sql    = isnull(@sql + ',', 'select ')
                + quotename(fieldname) + '=' + convert(varchar(10), startpos)
FROM    cteHour
order by startpos 

print   @sql

exec    sp_executesql @sql
...