将串行列拆分为每个值

时间:2018-04-21 21:42:58

标签: sql-server

我有一个包含多个列的表:

CREATE TABLE [dbo].[MyTable](
[ValueID] [int] NOT NULL,
[Timestamp] [datetime] NOT NULL,
[RealValue] [float] NOT NULL
) ON PRIMARY

+---------+----------------------+----------+
| ValueID | Timestamp            |RealValue |
+---------+----------------------+----------+
| 123     | 3/1/2018 12:00:49 AM | 54.1     |
| 123     | 3/1/2018 12:01:49 AM | 55.1     |
| 123     | 3/1/2018 12:02:49 AM | 56.1     |
| 123     | 3/1/2018 12:03:49 AM | 57.1     |
| 123     | 3/1/2018 12:04:49 AM | 58.1     |
| 876     | 3/1/2018 12:00:49 AM | 1.0      |
| 876     | 3/1/2018 12:01:49 AM | 1.1      |
| 876     | 3/1/2018 12:02:49 AM | 1.2      |
| 876     | 3/1/2018 12:03:49 AM | 1.3      |
| 876     | 3/1/2018 12:04:49 AM | 1.4      |
| 63      | 3/1/2018 12:00:49 AM | 300.0    |
| 63      | 3/1/2018 12:01:49 AM | 300.5    |
| 63      | 3/1/2018 12:02:49 AM | 301.0    |
| 63      | 3/1/2018 12:03:49 AM | 301.5    |
| 63      | 3/1/2018 12:04:49 AM | 302.0    |
+---------+----------------------+----------+

我需要将此表拆分为“每列值列”结构:

+----------------------+----------+----------+----------+
| Timestamp            | 123      | 876      | 63       |
+----------------------+----------+----------+----------+
| 3/1/2018 12:00:49 AM | 54.1     | 1.0      | 300.0    |
| 3/1/2018 12:01:49 AM | 55.1     | 1.1      | 300.5    |
| 3/1/2018 12:02:49 AM | 56.1     | 1.2      | 301.0    |
| 3/1/2018 12:03:49 AM | 57.1     | 1.3      | 301.5    |
| 3/1/2018 12:04:49 AM | 58.1     | 1.4      | 302.0    |
+----------------------+----------+----------+----------+

这可以用SQL,还是更适合脚本?

如:

SELECT DISTINCT [ValueID] FROM [db].[dbo].[MyTable]

//  ...Build a hash of distinct values in the script...

CREATE TABLE [dbo].[NewTable](
[123] int NOT NULL,
[876] int NOT NULL,
[63] int NOT NULL
...
) ON PRIMARY

//  ...Loop through hash and populate each column with a separate query...

该表相当大(2600万行),并且有大约500个不同的[ValueID]值,这些值将成为目标表中的列。

1 个答案:

答案 0 :(得分:0)

您可以使用pivot声明。

1。静态版

如果您有一定数量的ValueID值,您可以编写这样的查询(否则您应该使用动态解决方案来生成所有输出列):

if OBJECT_ID('MyTable') is null
  CREATE TABLE [dbo].[MyTable](
    [ValueID] [int] NOT NULL,
    [Timestamp] [datetime] NOT NULL,
    [RealValue] [float] NOT NULL
  )  
insert into [dbo].[MyTable]
          select 123     ,'20180301 12:00:49',54.1      
union all select 123     ,'20180301 12:01:49',55.1      
union all select 123     ,'20180301 12:02:49',56.1      
union all select 123     ,'20180301 12:03:49',57.1      
union all select 123     ,'20180301 12:04:49',58.1      
union all select 876     ,'20180301 12:00:49',1.0       
union all select 876     ,'20180301 12:01:49',1.1       
union all select 876     ,'20180301 12:02:49',1.2       
union all select 876     ,'20180301 12:03:49',1.3       
union all select 876     ,'20180301 12:04:49',1.4       
union all select 63      ,'20180301 12:00:49',300.0     
union all select 63      ,'20180301 12:01:49',300.5     
union all select 63      ,'20180301 12:02:49',301.0     
union all select 63      ,'20180301 12:03:49',301.5     
union all select 63      ,'20180301 12:04:49',302.0     

select piv.*
from 
( 
select ValueID,Timestamp,RealValue
from [dbo].[MyTable] 
) src 
pivot 
( 
max(realValue) 
for valueid in ([123], [876], [63])  -- If you have other valueids add them here
) piv 

此查询的结果:

enter image description here

2。动态版

如果您需要动态查询来自动创建所有ValueId值的所有列,您可以使用动态SQL,但要注意此方法的安全问题(SQL注入等)!

以下示例脚本可动态生成包含ValueID的所有列的查询:

if OBJECT_ID('MyTableDyn') is null
  CREATE TABLE [dbo].[MyTableDyn](
    [ValueID] [int] NOT NULL,
    [Timestamp] [datetime] NOT NULL,
    [RealValue] [float] NOT NULL
  )  
insert into [dbo].[MyTableDyn]
          select 123     ,'20180301 12:00:49',54.1      
union all select 123     ,'20180301 12:01:49',55.1      
union all select 123     ,'20180301 12:02:49',56.1      
union all select 123     ,'20180301 12:03:49',57.1      
union all select 123     ,'20180301 12:04:49',58.1      
union all select 876     ,'20180301 12:00:49',1.0       
union all select 876     ,'20180301 12:01:49',1.1       
union all select 876     ,'20180301 12:02:49',1.2       
union all select 876     ,'20180301 12:03:49',1.3       
union all select 876     ,'20180301 12:04:49',1.4       
union all select 63      ,'20180301 12:00:49',300.0     
union all select 63      ,'20180301 12:01:49',300.5     
union all select 63      ,'20180301 12:02:49',301.0     
union all select 63      ,'20180301 12:03:49',301.5     
union all select 63      ,'20180301 12:04:49',302.0     
union all select 99      ,'20180301 12:00:49',900.0     
union all select 99      ,'20180301 12:01:49',900.5     
union all select 99      ,'20180301 12:02:49',901.0     
union all select 99      ,'20180301 12:03:49',901.5     
union all select 99      ,'20180301 12:04:49',902.0  

declare @script nvarchar(max)=''
declare @ids nvarchar(max)=''
select @ids = @ids + ', ['+ cast([ValueID] as varchar(max)) + ']' 
  from [dbo].[MyTableDyn] 
  group by [ValueID]
set @ids = RIGHT(@ids, len(@ids)-2)

set @script = @script + 'select piv.*'
set @script = @script + ' from' 
set @script = @script + ' ( '
set @script = @script + ' select ValueID,Timestamp,RealValue'
set @script = @script + ' from [dbo].[MyTableDyn] '
set @script = @script + ' ) src '
set @script = @script + ' pivot '
set @script = @script + ' (' 
set @script = @script + ' max(realValue) '
set @script = @script + ' for valueid in (' + @ids +') '
set @script = @script + ' ) piv '

exec (@script) 

以下是结果(如您所见,出现ID为99的新列):

enter image description here