将行转置为列 SQL Server 2014
Transpose rows into columns SQL Server 2014
我有一个包含 51 列的 CSV 文件。
按此顺序,有一个 UID 列、序列列、日期列和一天中每个 30 分钟段的 48 列(从 00:30 到 00:00)。每天都有新的一行。
所以它看起来像:
UID | Serial | Date | Val_0030 | Val_0100 | Val_0130 | ..... | Val_0000
123 | 123456 | 2016-01-02 | 56.2 | 23.25 | 32.8 | ..... | 86.23
我需要将这些数据转置为 4 列,这样每半小时就有一个 UID、Serial 和 Date 列。换句话说,我需要 运行 向下而不是穿过。
看起来像这样:
UID | Serial | 2016-01-02 00:30 | Value
而不是像现在这样每天都有一个新行,我将确定 Val_0130 例如将确定时间为 01:30 并将与日期
我尝试过使用 pivot 和 unpivot,但没有成功。任何人都可以建议最好的方法来做到这一点。
我会使用 UNPIVOT
,然后剪切列名 Val_0130
以添加到日期时间以获得所需的结果。这样你只需要在一个地方写48列。
这里是一些测试数据:
DECLARE @Table AS TABLE (UID INT, Serial INT, Date DATETIME, Val_0030 MONEY, Val_0100 MONEY, Val_0130 MONEY, Val_0000 MONEY)
INSERT INTO @Table (UID, Serial, Date, Val_0030, Val_0100, Val_0130, Val_0000)
VALUES
(123, 123456, '2016-01-02',56.2,23.25,12.34,86.23)
,(231, 234561, '2016-01-05',26.2,13.25,23.45,106.23)
,(312, 345612, '2016-01-07',76.2,3.25,34.56,1010.56)
和查询
SELECT
UID
,Serial
,DateWithTime = [Date] + CAST((SUBSTRING(ColumnNames,5,2) + ':' + RIGHT(ColumnNames,2)) AS DATETIME)
,Value
FROM
@Table t
UNPIVOT (
Value
FOR ColumnNames IN (Val_0030, VAL_0100, Val_0130, VAL_0000)
) u
如果您不想输入所有 48 列,就像我不想的那样,只需 运行 此查询并将结果复制并粘贴到 ColumnNames IN ()
部分上面的查询。
DECLARE @ColString VARCHAR(MAX) = ''
DECLARE @DT DATETIME = '00:00'
WHILE @DT < '1900-01-02 00:00:00.000'
BEGIN
IF LEN(@ColString) > 0
BEGIN
SET @ColString += ','
END
SET @ColString += 'Val_' + FORMAT(@DT,'HHmm')
SET @DT = DATEADD(MINUTE,30,@DT)
END
SELECT @ColString
Matt 使用 UNPIVOT 提供了一个很好的答案。在无法选择的平台上,您可以使用交叉连接和 case 语句获得相同的效果。创建半小时的 table,并使用
生成值
select ...
, case hh.time when '00:00' then VAL_0000
when '00:30' then Val_0030
when '01:00' then Val_0100
when '01:30' then Val_0130
...
end as Value
from data cross join "half-hours" as hh
我有一个包含 51 列的 CSV 文件。
按此顺序,有一个 UID 列、序列列、日期列和一天中每个 30 分钟段的 48 列(从 00:30 到 00:00)。每天都有新的一行。 所以它看起来像:
UID | Serial | Date | Val_0030 | Val_0100 | Val_0130 | ..... | Val_0000
123 | 123456 | 2016-01-02 | 56.2 | 23.25 | 32.8 | ..... | 86.23
我需要将这些数据转置为 4 列,这样每半小时就有一个 UID、Serial 和 Date 列。换句话说,我需要 运行 向下而不是穿过。
看起来像这样:
UID | Serial | 2016-01-02 00:30 | Value
而不是像现在这样每天都有一个新行,我将确定 Val_0130 例如将确定时间为 01:30 并将与日期
我尝试过使用 pivot 和 unpivot,但没有成功。任何人都可以建议最好的方法来做到这一点。
我会使用 UNPIVOT
,然后剪切列名 Val_0130
以添加到日期时间以获得所需的结果。这样你只需要在一个地方写48列。
这里是一些测试数据:
DECLARE @Table AS TABLE (UID INT, Serial INT, Date DATETIME, Val_0030 MONEY, Val_0100 MONEY, Val_0130 MONEY, Val_0000 MONEY)
INSERT INTO @Table (UID, Serial, Date, Val_0030, Val_0100, Val_0130, Val_0000)
VALUES
(123, 123456, '2016-01-02',56.2,23.25,12.34,86.23)
,(231, 234561, '2016-01-05',26.2,13.25,23.45,106.23)
,(312, 345612, '2016-01-07',76.2,3.25,34.56,1010.56)
和查询
SELECT
UID
,Serial
,DateWithTime = [Date] + CAST((SUBSTRING(ColumnNames,5,2) + ':' + RIGHT(ColumnNames,2)) AS DATETIME)
,Value
FROM
@Table t
UNPIVOT (
Value
FOR ColumnNames IN (Val_0030, VAL_0100, Val_0130, VAL_0000)
) u
如果您不想输入所有 48 列,就像我不想的那样,只需 运行 此查询并将结果复制并粘贴到 ColumnNames IN ()
部分上面的查询。
DECLARE @ColString VARCHAR(MAX) = ''
DECLARE @DT DATETIME = '00:00'
WHILE @DT < '1900-01-02 00:00:00.000'
BEGIN
IF LEN(@ColString) > 0
BEGIN
SET @ColString += ','
END
SET @ColString += 'Val_' + FORMAT(@DT,'HHmm')
SET @DT = DATEADD(MINUTE,30,@DT)
END
SELECT @ColString
Matt 使用 UNPIVOT 提供了一个很好的答案。在无法选择的平台上,您可以使用交叉连接和 case 语句获得相同的效果。创建半小时的 table,并使用
生成值select ...
, case hh.time when '00:00' then VAL_0000
when '00:30' then Val_0030
when '01:00' then Val_0100
when '01:30' then Val_0130
...
end as Value
from data cross join "half-hours" as hh