Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 将一行表展平为键值对表_Sql_Tsql_Sql Server 2008_Pivot - Fatal编程技术网

Sql 将一行表展平为键值对表

Sql 将一行表展平为键值对表,sql,tsql,sql-server-2008,pivot,Sql,Tsql,Sql Server 2008,Pivot,获取表示行中列值的键值对结果集的最佳方法是什么 给定下表A,其中只有一行 Column1 Column2 Column3 ... Value1 Value2 Value3 也许你让事情变得比实际需要的更复杂了。部分原因是我无法将我的小脑袋围绕在PIVOT/UNPIVOT/的数量上,任何组合和动态SQL“红色海洋”都是实现这一点所必需的。因为您知道该表只有一行,所以提取每列的值可以只是一个子查询,作为一组UNIONed查询的一部分 DECLARE @sql NVARCHAR(MAX) =

获取表示行中列值的键值对结果集的最佳方法是什么

给定下表A,其中只有一行


Column1 Column2 Column3 ...
Value1  Value2  Value3

也许你让事情变得比实际需要的更复杂了。部分原因是我无法将我的小脑袋围绕在
PIVOT
/
UNPIVOT
/的数量上,任何组合和动态SQL“红色海洋”都是实现这一点所必需的。因为您知道该表只有一行,所以提取每列的值可以只是一个子查询,作为一组
UNION
ed查询的一部分

DECLARE @sql NVARCHAR(MAX) = N'INSERT dbo.B([Key], Value) '

SELECT @sql += CHAR(13) + CHAR(10) 
        + ' SELECT [Key] = ''' + REPLACE(name, '''', '''''') + ''', 
        Value = (SELECT ' + QUOTENAME(name) + ' FROM dbo.A) UNION ALL'
FROM sys.columns 
WHERE [object_id] = OBJECT_ID('dbo.A');

SET @sql = LEFT(@sql, LEN(@sql)-9) + ';';

PRINT @sql;
-- EXEC sp_executesql @sql;
结果(我只创建了4列,但这适用于任何数量的列):

世界上最有效率的事情?可能不会。但是,对于一行表,并且希望是一次性任务,我认为它可以很好地工作。只要留意包含撇号的列名,如果你允许这些东西出现在你的商店里


编辑很抱歉,不能这样处理。现在,它将处理列名中的撇号和其他次优命名选择。

我认为您已经完成了一半。只需按照Martin的建议使用
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)
结果

Key          Val
------------ ------------
Code         Foo
Name         Bar
Details      Baz
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)
当然,这里有一个警告。要使上述代码正常工作,所有列都必须是相同的数据类型。如果不是,则会出现以下错误:

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.
为了解决这个问题,您需要创建两个列字符串语句。一个用于获取列,另一个用于将它们全部转换为Val列的数据类型

对于多个列类型

Key          Val
------------ ------------
Code         Foo
Name         Bar
Details      Baz
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)

不涉及动态的版本。如果列名在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)
工作样本:

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)
结果:

Key                  Value
-------------------- -----
Column1              V1
Column2              V2
Column3              V3
更新

对于具有多个表的查询,可以使用
forxml 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)

这是一个
UNPIVOT
而不是
PIVOT
,但是您仍然需要动态SQL.+1作为Martin的注释。由于您不知道哪些列是未填充的,所以需要动态SQL。@Aaron-只是一个打字错误,现在必须承认,这是一个有趣的方法。我刚刚添加了
元素xsini
for
for
for XML PATH(“”),元素xsini,TYPE)作为T1(X)
以包含带有NULL的列。thanksMy dataset使用相同的列名联接多个表。是否有一种简单的方法可以获取包含表名的列名(而不必手动为所有内容添加别名)?
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)