kat*_*roh 9 sql t-sql pivot sql-server-2008
获取表示连续列值的键值对结果集的最佳方法是什么?
给出下面的表A只有1行
Column1 Column2 Column3 ...
Value1 Value2 Value3
Run Code Online (Sandbox Code Playgroud)
我想查询它并插入另一个表B:
Key Value
Column1 Value1
Column2 Value2
Column3 Value3
Run Code Online (Sandbox Code Playgroud)
表A中的一组列事先不知道.
注意:我正在查看FOR XML和PIVOT功能以及动态SQL来执行以下操作:
DECLARE @sql nvarchar(max)
SET @sql = (SELECT STUFF((SELECT ',' + column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name='TableA'
ORDER BY column_name FOR XML PATH('')), 1, 1, ''))
SET @sql = 'SELECT ' + @sql + ' FROM TableA'
EXEC(@sql)
Run Code Online (Sandbox Code Playgroud)
Mik*_*son 18
没有动态的版本.如果您的列名无效,无法用作XML中的元素名称,则会失败.
select T2.N.value('local-name(.)', 'nvarchar(128)') as [Key],
T2.N.value('text()[1]', 'nvarchar(max)') as Value
from (select *
from TableA
for xml path(''), type) as T1(X)
cross apply T1.X.nodes('/*') as T2(N)
Run Code Online (Sandbox Code Playgroud)
一份工作样本:
declare @T table
(
Column1 varchar(10),
Column2 varchar(10),
Column3 varchar(10)
)
insert into @T values('V1','V2','V3')
select T2.N.value('local-name(.)', 'nvarchar(128)') as [Key],
T2.N.value('text()[1]', 'nvarchar(max)') as Value
from (select *
from @T
for xml path(''), type) as T1(X)
cross apply T1.X.nodes('/*') as T2(N)
Run Code Online (Sandbox Code Playgroud)
结果:
Key Value
-------------------- -----
Column1 V1
Column2 V2
Column3 V3
Run Code Online (Sandbox Code Playgroud)
更新
对于具有多个表的查询,您可以使用它for xml auto来获取XML中的表名.请注意,如果在查询中使用表名的别名,则会获得别名.
select X2.N.value('local-name(..)', 'nvarchar(128)') as TableName,
X2.N.value('local-name(.)', 'nvarchar(128)') as [Key],
X2.N.value('text()[1]', 'nvarchar(max)') as Value
from (
-- Your query starts here
select T1.T1ID,
T1.T1Col,
T2.T2ID,
T2.T2Col
from T1
inner join T2
on T1.T1ID = T2.T1ID
-- Your query ends here
for xml auto, elements, type
) as X1(X)
cross apply X1.X.nodes('//*[text()]') as X2(N)
Run Code Online (Sandbox Code Playgroud)
我想你已到了一半.只需使用UNPIVOT和dynamic SQL马丁推荐:
CREATE TABLE TableA (
Code VARCHAR(10),
Name VARCHAR(10),
Details VARCHAR(10)
)
INSERT TableA VALUES ('Foo', 'Bar', 'Baz')
GO
DECLARE @sql nvarchar(max)
SET @sql = (SELECT STUFF((SELECT ',' + column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name='TableA'
ORDER BY ordinal_position FOR XML PATH('')), 1, 1, ''))
SET @sql = N'SELECT [Key], Val FROM (SELECT ' + @sql + ' FROM TableA) x '
+ 'UNPIVOT ( Val FOR [Key] IN (' + @sql + ')) AS unpiv'
EXEC (@sql)
Run Code Online (Sandbox Code Playgroud)
结果:
Key Val
------------ ------------
Code Foo
Name Bar
Details Baz
Run Code Online (Sandbox Code Playgroud)
当然有一个警告.您的所有列都需要与上述代码相同的数据类型才能工作.如果不是,您将收到此错误:
Msg 8167, Level 16, State 1, Line 1
The type of column "Col" conflicts with the type of
other columns specified in the UNPIVOT list.
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,您需要创建两个列字符串语句.一个用于获取列,另一个用于将它们全部转换为Val列的数据类型.
对于多列类型:
CREATE TABLE TableA (
Code INT,
Name VARCHAR(10),
Details VARCHAR(10)
)
INSERT TableA VALUES (1, 'Foo', 'Baf')
GO
DECLARE
@sql nvarchar(max),
@cols nvarchar(max),
@conv nvarchar(max)
SET @cols = (SELECT STUFF((SELECT ',' + column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name='TableA'
ORDER BY ordinal_position FOR XML PATH('')), 1, 1, ''))
SET @conv = (SELECT STUFF((SELECT ', CONVERT(VARCHAR(50), '
+ column_name + ') AS ' + column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name='TableA'
ORDER BY ordinal_position FOR XML PATH('')), 1, 1, ''))
SET @sql = N'SELECT [Key], Val FROM (SELECT ' + @conv + ' FROM TableA) x '
+ 'UNPIVOT ( Val FOR [Key] IN (' + @cols + ')) AS unpiv'
EXEC (@sql)
Run Code Online (Sandbox Code Playgroud)