Поворот или CTE для поворота / изменения данных на основе даты и времени из строк в именованные столбцы - PullRequest
0 голосов
/ 20 сентября 2018
SELECT 
    SerialNumber AS 'Serial', 
    ChannelName AS 'Channel', 
    CAST(ReadingDate AS DATE) AS 'ReadingDate', 
    CAST(ReadingDate AS TIME(0)) AS 'ReadingTime',
    ChannelValue AS 'Value'
FROM 
    [Staging].[UriData]
WHERE 
    ChannelName IN (SELECT ChannelName FROM Staging.ActiveChannels)     
    AND Processed = 0   
ORDER BY 
    ReadingDate DESC, ReadingTime DESC

Вывод:

Serial  |  Channel  |  ReadingDate  |  ReadingTime  |  Value
--------+-----------+---------------+---------------+-------
2209         m1         2018-09-20      16:30:00       20497
2209         m10        2018-09-20      16:30:00       20497
2209         m11        2018-09-20      16:30:00       1
2209         m2         2018-09-20      16:30:00       1
2209         m3         2018-09-20      16:30:00       2447
2209         m4         2018-09-20      16:30:00       0
2209         m5         2018-09-20      16:30:00       6490
2209         m6         2018-09-20      16:30:00       0
2209         m7         2018-09-20      16:30:00       50
2209         m7         2018-09-20      16:15:00       50
2209         m6         2018-09-20      16:15:00       0
2209         m5         2018-09-20      16:15:00       6620
2209         m4         2018-09-20      16:15:00       0
2209         m3         2018-09-20      16:15:00       2440
2209         m2         2018-09-20      16:15:00       1
2296         m11        2018-09-20      16:15:00       1
2296         m10        2018-09-20      16:15:00       20490
1489         m1         2018-09-20      16:15:00       20490
1489         m1         2018-09-20      16:00:00       20483
1489         m10        2018-09-20      16:00:00       20483

Поворот таблицы для получения:

--------------------------------------------------------------------------
Serial  |  Channel  |  ReadingDate  |  00:15  |  00:30  |  00:45.....00:00   
--------------------------------------------------------------------------
2209         m1         2018-09-20       56        987      65         234  
2209         m2         2018-09-20      etc.
2209         m3         2018-09-20     
2209         m4         2018-09-20      
2209         m5         2018-09-20      
1489         m6         2018-09-20      
1489         m7         2018-09-20      
2209.... etc.

Кто-то помог мне в предыдущем вопросе, на который был дан ответ, но я действительно не понимаю, чтоони написали и нашли это очень сложным.Я не хочу просто копировать чей-то код, но понимаю, как это достигается.Несмотря на то, что я выполнил набор учебных пособий, этот результат, который мне требуется, по-видимому, не охвачен, или я неправильно понимаю принципы.

Предыдущий вопрос и ответ

Тамможет быть несколько разных серийных номеров, разных названий каналов и разных дат.Но всегда будет 96 значений для дня, превышающего полночь до полуночи (2018-01-01 от 00:01 до 2018-01-02 00:00).

Таким образом, новые столбцы - это время чтениязаполнено соответствующим значением, по дате, серийному номеру и каналу.Первоначальный запрос гарантирует, что отправленные назад каналы существуют в таблице имен каналов.

Что я использую, некоторые говорят CTE, некоторые говорят Pivot, некоторые говорят, что используют SSIS.Я действительно борюсь с концепцией этого.

Любая помощь, указатели или советы будут оценены, поэтому я могу сосредоточить свои знания в этой области.

1 Ответ

0 голосов
/ 21 сентября 2018

Запрос, используемый в @ 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>&lt; и т. Д.)

Вы также можете достичь того же результата, используя PIVOT конструкцияСм. мой ответ на ваш предыдущий вопрос.

Надеюсь, это поможет.

...