将动态 table 列反透视为键值行
Unpivot dynamic table columns into key value rows
我需要解决的问题是数据从一个具有许多动态字段的 table 传输到另一个结构化键值 table。
第一个 table 来自另一个系统的数据导出,具有以下结构(它可以具有任何列名和数据):
[UserID],[FirstName],[LastName],[Email],[你今天过得怎么样],[你想收到每周通讯吗],[确认你年满 18 岁] ...
第二个table是我要放数据的地方,结构如下:
[用户 ID uniqueidentifier]、[问题文本 nvarchar(500)]、[问题答案 nvarchar(max)]
我看到很多示例展示了如何逆透视 table,但我的问题是我不知道 Table 1 会有哪些列。我能以某种方式动态地反转第一个 table,所以无论它有什么列,它都会转换为键值结构并将数据导入第二个 table.
非常感谢您对此的帮助。
您无法在不知道列的情况下在一个查询中旋转或取消旋转。
假设您有特权,您可以做的是查询 sys.columns
以获取源的字段名称 table,然后动态构建一个逆透视查询。
--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
将数据放入 table,然后检查 table 的列名字。此 link 显示了如何执行该部分。
最后说明:如果您使用临时 table,请记住您从 tempdb.sys.columns
中获取列名,如下所示:
select column_id, name
from tempdb.sys.columns
where object_id = object_id('tempdb..#MyTable','U')
我需要解决的问题是数据从一个具有许多动态字段的 table 传输到另一个结构化键值 table。 第一个 table 来自另一个系统的数据导出,具有以下结构(它可以具有任何列名和数据): [UserID],[FirstName],[LastName],[Email],[你今天过得怎么样],[你想收到每周通讯吗],[确认你年满 18 岁] ...
第二个table是我要放数据的地方,结构如下: [用户 ID uniqueidentifier]、[问题文本 nvarchar(500)]、[问题答案 nvarchar(max)]
我看到很多示例展示了如何逆透视 table,但我的问题是我不知道 Table 1 会有哪些列。我能以某种方式动态地反转第一个 table,所以无论它有什么列,它都会转换为键值结构并将数据导入第二个 table.
非常感谢您对此的帮助。
您无法在不知道列的情况下在一个查询中旋转或取消旋转。
假设您有特权,您可以做的是查询 sys.columns
以获取源的字段名称 table,然后动态构建一个逆透视查询。
--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
将数据放入 table,然后检查 table 的列名字。此 link 显示了如何执行该部分。
最后说明:如果您使用临时 table,请记住您从 tempdb.sys.columns
中获取列名,如下所示:
select column_id, name
from tempdb.sys.columns
where object_id = object_id('tempdb..#MyTable','U')