Sql server 动态sql将具有一行的列名转换为具有两列和多行的表
在使用PIVOT、cross-join等搜索了几种将列转换为行的方法之后,我的问题仍然没有得到回答 我有一个返回1行和147列的结果集Sql server 动态sql将具有一行的列名转换为具有两列和多行的表,sql-server,Sql Server,在使用PIVOT、cross-join等搜索了几种将列转换为行的方法之后,我的问题仍然没有得到回答 我有一个返回1行和147列的结果集 ID | Name | DOB | BloodGroup | ...... 147 columns 1 XYZ 17MAY A+ ...... 我的目标是将此结果集转换为2列和147行 Column_Name | Value ID 1 NAME XYZ :
ID | Name | DOB | BloodGroup | ...... 147 columns
1 XYZ 17MAY A+ ......
我的目标是将此结果集转换为2列和147行
Column_Name | Value
ID 1
NAME XYZ
: :
我该怎么做呢?感谢您的反馈这被称为
unpivot
。从概念上讲,最简单的方法是:
select 'id' as column_name, cast(id as varchar(255)) as column_value
from Result
union all
select 'name', name
from Result
union all
. . .
这可能会很麻烦。如果result
是一个表,则可以使用information\u schema.columns
创建SQL,类似于:
select 'select ''' + column_name + ''' as column_name, cast(' + column_name + ' as varchar(255)) as column_value from result union all'
from information_schema.columns
where table_name = 'Result'
此方法不是最有效的方法,因为它需要读取每列的表。因此,
unpivot
是更好的方法。语法已被描述。我采用了Gordon在其文章中提到的第二种方法,但从中构建了动态SQL。我交叉连接了几个sys表连接的结果和一个源表,然后根据列名构建了一个CASE语句。我将其合并为动态SQL,然后执行它。为了简单起见,我将所有变量项都变成了变量,您可以在例程开始时填写这些变量。代码如下:
USE AdventureWorks2012;
GO
DECLARE @MySchema VARCHAR(100),
@MyTable VARCHAR(100),
@MyUIDColumn VARCHAR(100),
@MyFieldsMaxLength VARCHAR(10),
@SQL AS VARCHAR(MAX);
SET @MySchema = 'Person';
SET @MyTable = 'Person';
-- Unique ID which routine will identify unique entities by. Will also sort on this value in the end result dataset.
SET @MyUIDColumn = 'BusinessEntityID';
-- This determines the max length of the fields you will cast in your Value column.
SET @MyFieldsMaxLength = 'MAX';
WITH cteSQL
AS
(
SELECT 1 AS Sorter, 'SELECT c.name AS ColumnName,' AS SQL
UNION ALL
SELECT 2, 'CASE' AS Statement
UNION ALL
SELECT 3, 'WHEN c.name = ''' + c.name + ''' THEN CAST(mt.' + c.name + ' AS VARCHAR(' + @MyFieldsMaxLength + ')) '
FROM sys.tables t INNER JOIN sys.columns c
ON t.object_id = c.object_id
WHERE t.name = @MyTable
UNION ALL
SELECT 4, 'END AS Value' AS Statement
UNION ALL
SELECT 5, 'FROM sys.tables t INNER JOIN sys.columns c ON t.object_id = c.object_id INNER JOIN sys.schemas s ON t.schema_id = s.schema_id, ' + @MySchema + '.' + @MyTable + ' mt WHERE t.name = ''' + @MyTable + ''' AND s.name = ''' + @MySchema + ''' ORDER BY mt. ' + @MyUIDColumn + ', c.name;'
)
SELECT @SQL =
(
SELECT SQL + ' '
FROM cteSQL
ORDER BY Sorter
FOR XML PATH ('')
);
EXEC(@SQL);
我真的说不出执行时间会是什么样子。我在本地机器上对AdventureWorks2012 Person.Person表(约20k行,13列)运行了它,它在大约8秒内恢复了约250万行,如果这意味着什么的话。好的是,它可以灵活地无缝地处理任何表格。不管怎样,我只是觉得这是一个有趣的拼图游戏,所以决定玩一玩。希望能有帮助
编辑:仔细想想,这可能比Gordon提出的方法还要慢,但我确实做到了。哦,好吧。(是的,他的方法在大约一半的时间内都能奏效。对我没有多大帮助。)谢谢你的回复 我想出了一个办法
我在一个逗号分隔的字符串变量中得到了所有列名。2.将相同的字符串传递给UNPIVOT对象。通过这种方法,完全避免了对140个列名进行硬编码 您期望的样本输出是什么?目前还不太清楚。是否要在第二个输出列中显示列名和列值?它将分别有两列,即ColumnName和value。ColumnName下是所有列名称,如ID、Name、DOB等,其中values列中是它们各自的值。您试图实现的是什么,而行形式的数据无法实现?请从information_schema.columns where table_Name='XYZ'中选择column_Name。此查询提供一行下的所有列名。我需要弄清楚的是,如何提取与列名对应的值。至于Daniel的回答,答案是否定的。我特别需要该结构,它需要连接到另一个表。我已经想到了这种方法。然而,这并不是最好的方法。谢谢你的努力!