Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server Pivot或CTE将基于日期和时间的数据从行透视/更改为命名列_Sql Server_Pivot_Pivot Table_Common Table Expression - Fatal编程技术网

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)