我已经坚持了一段时间,而且我没有在网站上找到回答这类内容的东西,所以如果现有问题存在,请指出正确的方向。在SQL Server 2012中,我有一个以ID作为主键的表:
ID col1 col2 col3 ....
--- ---- ----- -----
1 a z k
2 g b p
3 k d a
我不知道表的长度,也不知道列/列名的数量 但是我希望能得到一张能给我这样的表格:
ID ColName Value
--- ---- -----
1 col1 a
1 col2 z
1 col3 k
2 col1 g
2 col2 b
2 col3 p
3 col1 k
3 col2 d
3 col3 a
...
我知道
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = 'table'
获取我的列,我尝试使用它来创建临时表 将我想要的格式插入到临时表中,但我不确定如何遍历表中的每一行,然后为每个列名动态获取所需的值并显示它。我已经能够用双游标实现这一点,但这很慢,而且我不确定如何处理这个问题,因为我在SQL方面相对较新。任何帮助将不胜感激!
修改
非常感谢Lamak!我确实有不同的数据类型,并将它们转换为varchars现在告诉我这个概念确实有效。但是,我有4种常见的数据类型(varchar,float,int,datetime),所以我有4个值字段,每个我将根据它将列值插入其中一个4并保留其他3个空白。我知道INFORMATION_SCHEMA.COLUMNS也提供了data_types,所以我想知道基于简单的IF语句转换“STUFF”变量中的数据类型的语法是什么。我尝试将data_types映射到列名,但是使用任何类型的条件语句都会破坏查询。如果有人有一个简单的例子,那就太好了:)
修改 实际上,我已经能够弄清楚我需要为每种数据类型创建4个变量,而不是仅在其中一个数据类型中创建它们。谢谢大家的帮助!
答案 0 :(得分:1)
正如评论所说,你需要使用动态unpivot。
如果ID
旁边的每个列都具有相同的数据类型,则可以使用以下查询:
DECLARE @colsUnpivot AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
SELECT @colsUnpivot = STUFF((SELECT ', ' + QUOTENAME(C.name)
FROM sys.columns as C
WHERE C.object_id = object_id('table') AND
C.name <> 'ID'
FOR XML PATH('')), 1, 1, '');
SET @query = '
SELECT ID,
ColName,
Value
FROM
(
SELECT *
FROM dbo.table
) x
UNPIVOT
(
Value FOR ColName IN (' + @colsunpivot + ')
) u
';
EXEC(@query);
现在,如果数据类型不同,那么您需要先将每个列转换为通用数据类型。在以下示例中,我将使用NVARCHAR(1000)
,但您需要将它们转换为正确的数据类型:
DECLARE @colsUnpivot1 AS NVARCHAR(MAX),
@colsUnpivot2 as NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
SELECT @colsUnpivot1 = STUFF((SELECT ', ' + QUOTENAME(C.name)
FROM sys.columns as C
WHERE C.object_id = object_id('table') AND
C.name <> 'ID'
FOR XML PATH('')), 1, 1, '');
SELECT @colsUnpivot2 = STUFF((SELECT ', CONVERT(NVARCHAR(1000),' + QUOTENAME(C.name)
+ ') ' + QUOTENAME(C.name)
FROM sys.columns as C
WHERE C.object_id = object_id('table') AND
C.name <> 'ID'
FOR XML PATH('')), 1, 1, '');
SET @query = '
SELECT ID,
ColName,
Value
FROM
(
SELECT ID, ' + @colsUnpivot2 + '
FROM dbo.table
) x
UNPIVOT
(
Value FOR ColName IN ('+ @colsunpivot1 +')
) u
';
EXEC(@query);
答案 1 :(得分:0)
你不必去DYNAMIC。带有CROSS APPLY和一点XML的另一个选项。
UnPivot性能更高,但你会发现这种方法的表现非常可观。
这种方法的另一个好处是Connection keep-alive
Content-Length 9437
Content-Type text/html;charset=UTF-8
Date Tue, 28 Mar 2017 21:16:46 GMT
可以是任何查询(不限于表格)。例如From @YourTable A
From ( -- Your Complex Query --) A
返回
Declare @YourTable table (ID int,Col1 varchar(25),Col2 varchar(25),Col3 varchar(25))
Insert Into @YourTable values
(1,'a','z','k')
,(2,'g','b','p')
,(3,'k','d','a')
Select C.*
From @YourTable A
Cross Apply (Select XMLData=cast((Select A.* for XML Raw) as xml)) B
Cross Apply (
Select ID = r.value('@ID','int')
,Item = attr.value('local-name(.)','varchar(100)')
,Value = attr.value('.','varchar(max)')
From B.XMLData.nodes('/row') as A(r)
Cross Apply A.r.nodes('./@*') AS B(attr)
Where attr.value('local-name(.)','varchar(100)') not in ('ID','OtherFieldsToExclude')
) C