【问题标题】:Unpivot dynamic table columns into key value rows将动态表列反透视为键值行
【发布时间】:2015-08-27 20:26:03
【问题描述】:

我需要解决的问题是从一个包含许多动态字段的表到另一个结构化键值表的数据传输。 第一个表来自另一个系统的数据导出,具有以下结构(它可以有任何列名和数据): [UserID],[FirstName],[LastName],[Email],[你今天过得怎么样],[你想收到每周简报吗],[确认你 18 岁以上] ...

第二个表是我要放置数据的地方,它的结构如下: [UserID uniqueidentifier],[QuestionText nvarchar(500)],[Question Answer nvarchar(max)]

我看到了许多展示如何取消透视表的示例,但我的问题是我不知道表 1 将包含哪些列。我能否以某种方式动态反透视第一个表,所以无论它有什么列,它都会转换为键值结构并将数据导入到第二个表中。

非常感谢您在这方面的帮助。

【问题讨论】:

  • 请发布一些示例数据和预期结果。

标签: sql-server tsql data-migration unpivot cross-apply


【解决方案1】:

在不知道列的情况下,您无法在一个查询中进行透视或取消透视。

假设您有权限,您可以做的是查询 sys.columns 以获取源表的字段名称,然后动态构建一个非透视查询。

--Source table
create table MyTable (
    id int,
    Field1 nvarchar(10),
    Field2 nvarchar(10),
    Field3 nvarchar(10)
);

insert into MyTable (id, Field1, Field2, Field3) values ( 1, 'aaa', 'bbb', 'ccc' );
insert into MyTable (id, Field1, Field2, Field3) values ( 2, 'eee', 'fff', 'ggg' );
insert into MyTable (id, Field1, Field2, Field3) values ( 3, 'hhh', 'iii', 'jjj' );

--key/value table
create table MyValuesTable (
    id int,
    [field] sysname,
    [value] nvarchar(10)
);



declare @columnString nvarchar(max)

--This recursive CTE examines the source table's columns excluding
--the 'id' column explicitly and builds a string of column names
--like so: '[Field1], [Field2], [Field3]'.

;with columnNames as (
  select column_id, name
  from sys.columns 
  where object_id = object_id('MyTable','U')
    and name <> 'id'
),
columnString (id, string) as (
  select
    2, cast('' as nvarchar(max))
  union all
  select
    b.id + 1, b.string + case when b.string = '' then '' else ', ' end + '[' + a.name + ']'
  from
    columnNames a
    join columnString b on b.id = a.column_id
)
select top 1 @columnString = string from columnString order by id desc

--Now I build a query around the column names which unpivots the source and inserts into the key/value table.
declare @sql nvarchar(max)
set @sql = '
insert MyValuestable
select id, field, value
from
  (select * from MyTable) b
unpivot
  (value for field in (' + @columnString + ')) as unpvt'

--Query's ready to run.
exec (@sql)

select * from MyValuesTable

如果您从存储过程中获取源数据,可以使用OPENROWSET 将数据放入表中,然后检查该表的列名。此链接显示了如何执行该部分。 https://stackoverflow.com/a/1228165/300242

最后说明:如果您使用临时表,请记住您从 tempdb.sys.columns 获取列名,如下所示:

select column_id, name
from tempdb.sys.columns 
where object_id = object_id('tempdb..#MyTable','U')

【讨论】:

  • 非常感谢@JC。这对我来说效果很好。非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多