在搜索了几种使用PIVOT,交叉连接等将列转换为行的方法后,我的问题仍未得到解答
我有一个返回1行和147列的结果集
ID | Name | DOB | BloodGroup | ...... 147 columns
1 XYZ 17MAY A+ ......
我的目标是将此结果集转换为2列和147行
Column_Name | Value
ID 1
NAME XYZ
: :
我应该怎么做?感谢您的反馈
答案 0 :(得分:1)
我采用了Gordon在帖子中提到的第二种方法,但是从中构建了动态SQL。我CROSS JOIN了几个sys表JOIN和一个源表的结果,然后从列名中建立一个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万行,如果这意味着什么。好处是它可以灵活地无缝地接收任何表格。无论如何,只是觉得这是一个有趣的拼图,所以决定玩一下。希望它有所帮助。
编辑:考虑一下,这可能比戈登提出的方法要慢,但我做得很好。那好吧。 (是的,他的方法在大约一半的时间内起作用。获得幻想对我帮助不大。)
答案 1 :(得分:0)
这称为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_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
是更好的方法。语法描述为here。
答案 2 :(得分:0)
感谢您的回复。
我想出了一种方法。
我在逗号分隔的字符串变量中得到了所有列名。 2.将相同的字符串传递给UNPIVOT对象。通过这种方法,完全避免了140列名称的硬编码。