Sql server Pivot或CTE将基于日期和时间的数据从行透视/更改为命名列
输出:Sql server Pivot或CTE将基于日期和时间的数据从行透视/更改为命名列,sql-server,pivot,pivot-table,common-table-expression,Sql Server,Pivot,Pivot Table,Common Table Expression,输出: 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 Channel
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
有人帮我回答了之前的一个问题,但我真的不明白他们写了什么,觉得很复杂。我不想只是复制别人的代码,但要理解这是如何实现的。虽然我已经做了一堆教程,但我要求的结果似乎没有涵盖,或者我误解了原则
可能有几个不同的序列号、不同的频道名称和不同的日期。但在午夜之前(2018-01-01 00:01至2018-01-02 00:00),大于午夜的一天始终有96个值
因此,新列是由日期、序列和通道填充相应值的读取时间。初始查询确保发送回的通道存在于通道名称表中
我使用什么,一些人说CTE,一些人说Pivot,一些人说使用SSI。我真的很难理解这个概念
任何帮助、指点或建议都将不胜感激,以便我能够将我的知识集中到该领域。在@D-Shih中使用的查询是一个“”查询。在SQL 2008之前,没有构造,因此使用了另一种方法,即采用groupby
。在SQL Server的更高版本中,这仍然是一种有效的方法,尽管它更加冗长
他的查询生成“最终查询”,然后执行该查询以给出结果。在您的情况下,您实际上不需要使用动态查询,但正如您将看到的那样,最终的查询非常大,手工键入它将是一个长期且容易出错的练习
理解一堆语句的作用的方法是一次运行一个语句,看看结果是什么
我将以@D-Shih为例
让我们看一下第一个CTE(公共表表达式),它也被命名为CTE:
--------------------------------------------------------------------------
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.
然后运行两个语句以获得:
SELECT * FROM CTE
从以上结果可以看出,startDt
列有一组“时间”
接下来我们看一下时间表
。请注意,timeline
CTE在其前面引用了“CTE”表达式,因此要查看结果,需要同时运行它们,然后按如下所示运行select查询:
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
请注意,已添加了rn
(行号)列。请注意,此列是一个“排序”列,即此列中的值随着startDt
值的增加而增加
接下来,您可以运行此查询(注意,为了简洁起见,我已对CTE表进行了修改):
将@cols声明为NVARCHAR(MAX),
@查询为NVARCHAR(最大值);
[CTE表达式位于此处]
选择@cols=CONCAT(@cols,'MAX(CASE WHEN“”)+CAST(startDt AS VARCHAR(5))+'''=CAST(ReadingDate AS TIME),然后选择ChannelValue ELSE 0 end)AS',QUOTENAME(CAST(startDt AS VARCHAR(5)),,')
根据时间表
其中startDt CTE(用于公共表表达式)是编写子查询(并使其更易于阅读)的一种方法,或者是执行递归查询的一种方法。在前面的示例中,解决方案使用递归CTE。他们还使用了排名功能,这是用来动态添加行数,排名。。。这是用来对结果排序的。他们说他们被使用了。这不是“真正的”支点。他们建立一个动态查询,指定列名。这是一个巨大的帮助。我使用了Pivot方法,它很有效,但有一个问题。查询不会在“2018-09-20 00:00”行的末尾显示值,而是在“2018-09-21 00:00”处为值创建新行。与“2018-09-20 00:00”有一行96个值不同,在示例中有两行,一行95个值表示“2018-09-20 00:00”,一行为null,另一行95个null,最后一行为“2018-09-21 00:00”,日期和时间列作为字符串:[ReadingDate]varchar(10),[ReadingTime]varchar(8)
,这不是最佳选择。分别使用CONVERT(DATE,ReadingDate,103),CONVERT(TIME,[ReadingTime])
将它们转换为DATE
和TIME
。
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
;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
...
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)