Запрос, используемый в @ D-Shih answer , является запросом " old style pivot ".До SQL 2008 не было конструкции PIVOT
, поэтому использовался альтернативный подход, который использовал GROUP BY
.Это все еще допустимый подход в более поздних версиях SQL Server, хотя он более подробный.
Его запрос генерирует «окончательный запрос», который затем выполняется, чтобы дать вам результат.В вашем случае вам на самом деле не нужно использовать динамический запрос, но, как вы увидите, окончательный запрос довольно велик, и ввод его вручную будет долгим и подверженным ошибкам упражнением.
Способ понятьто, что делает куча операторов, - это запускать их по одному и смотреть, каков будет результат.
Я буду использовать @ D-Shih answer в качестве примера.
Давайте посмотрим на первое CTE (Common Table Expression), которое также называется CTE:
;WITH CTE AS (
SELECT CAST('00:00' AS TIME) startDt, CAST('23:45' AS TIME) endDt
UNION ALL
SELECT DATEADD(MINUTE, 15, startDt),endDt
FROM CTE
WHERE DATEADD(MINUTE, 15, startDt) <endDt
)
Это рекурсивное Common Table Expression.Вы можете прочитать больше о них здесь .Чтобы увидеть, какие результаты дает приведенный выше оператор, вы можете просто добавить
SELECT * FROM CTE
сразу после него и запустить оба оператора, чтобы получить:
startDt endDt
---------------- ----------------
00:00:00.0000000 23:45:00.0000000
00:15:00.0000000 23:45:00.0000000
00:30:00.0000000 23:45:00.0000000
00:45:00.0000000 23:45:00.0000000
01:00:00.0000000 23:45:00.0000000
...
23:30:00.0000000 23:45:00.0000000
Из приведенных выше результатов видно, что startDt
столбец имеет набор «времен».
Далее мы рассмотрим TimeTable
.Обратите внимание, что TimeTable
CTE ссылается на выражение «CTE» перед ним, поэтому, чтобы увидеть результаты, вам нужно запустить их оба, а затем выполнить запрос select следующим образом:
;WITH CTE AS (
SELECT CAST('00:00' AS TIME) startDt, CAST('23:45' AS TIME) endDt
UNION ALL
SELECT DATEADD(MINUTE, 15, startDt),endDt
FROM CTE
WHERE DATEADD(MINUTE, 15, startDt) <endDt
), TimeTable AS (
select *,ROW_NUMBER() OVER (ORDER BY startDt) rn
FROM (
SELECT startDt,endDt
FROM CTE
UNION ALL
SELECT CAST('23:45' AS TIME) startDt, CAST('23:45' AS TIME) endDt
) t1
)
SELECT * FROM TimeTable
Вы получите
startDt endDt rn
---------------- ---------------- --------------------
00:00:00.0000000 23:45:00.0000000 1
00:15:00.0000000 23:45:00.0000000 2
00:30:00.0000000 23:45:00.0000000 3
00:45:00.0000000 23:45:00.0000000 4
...
Обратите внимание, что добавлен столбец rn
(номер строки).Обратите внимание, что этот столбец является столбцом «сортировки», т. Е. Значения в этом столбце увеличиваются при увеличении значений startDt
.
Далее вы можете выполнить этот запрос (обратите внимание, я для краткости опускаю таблицы CTE):
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
[CTE Expression goes here]
select @cols = CONCAT(@cols,'MAX(CASE WHEN '''+CAST(startDt AS VARCHAR(5))+''' = CAST(ReadingDate AS TIME) THEN ChannelValue ELSE 0 end) AS ',QUOTENAME(CAST(startDt AS VARCHAR(5))),', ')
from TimeTable
WHERE startDt <= endDt
ORDER BY rn
SET @cols = left(@cols, len(@cols) - 1)
-- Print value of a single variable
SELECT CAST('<A><![CDATA[' + CAST(@cols as nvarchar(max)) + ']]></A>' AS xml)
Сложный CAST('<A><![CDATA[' + CAST(@cols as nvarchar(max)) + ']]></A>' AS xml)
необходим, чтобы обойти проблему усечения вывода текста в SSMS (см. здесь )
Наконец, вы можете сразу выполнить полный запрос, за исключением необходимости заменитьexec(@query)
с SELECT CAST('<A><![CDATA[' + CAST(@query as nvarchar(max)) + ']]></A>' AS xml)
для просмотра окончательного запроса (обратите внимание, что текст в кодировке XML, т. Е. <Заменяется на <code>< и т. Д.)
Вы также можете достичь того же результата, используя PIVOT
конструкцияСм. мой ответ на ваш предыдущий вопрос.
Надеюсь, это поможет.