数据的组合半转置
Combined Semi-transpose of a data
考虑以下查询:
DECLARE @T1 TABLE(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Data] VARCHAR(100),
[Column1] VARCHAR(100),
[Column2] VARCHAR(100),
[Column3] VARCHAR(100));
INSERT INTO @T1([Data],[Column1],[Column2],[Column3])
VALUES
('Data1','C11','C21','C31'),
('Data2','C12','C22','C32'),
('Data3','C13','C23','C33'),
('Data4','C14','C24','C34'),
('Data5','C15','C25','C35');
SELECT * FROM @T1;
输出如下所示:
现在我们想要保留数据列,并且对于每个其他列,将该列的 select 的结果堆叠到最终的 table 中。换句话说,以下查询产生输出:
-- I am looking for a better solution than below!
DECLARE @output TABLE([Data] VARCHAR(100),[Column] VARCHAR(100));
INSERT INTO @output([Data],[Column])
(SELECT [Data],[Column1] FROM @T1
UNION
SELECT [Data],[Column2] FROM @T1
UNION
SELECT [Data],[Column3] FROM @T1)
SELECT * FROM @output
有什么比上述方法更清洁的方法来生成最终输出?随着列数的增加,这意味着对于每个新列,我都需要有一个单独的插入物,这似乎是一个粗略的解决方案。理想情况下,我正在寻找一个基于枢轴的解决方案,但我想不出具体的东西。
我经常使用 apply
而不是 union
:
select t1.data, t2.cols
from @t1 t1 cross apply
( values ([column1]), ([column2]), ([column3]) ) t2(cols);
当然,Yogesh 的解决方案会更高效。但是,由于您的列会随着时间的推移而扩展,这里有一种方法可以 "dynamically" 逆透视您的数据 WITHOUT 实际上使用 Dynamic SQ:
例子
Select A.[Data]
,C.*
From @T1 A
Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
Cross Apply (
Select Item = xAttr.value('local-name(.)', 'varchar(100)')
,Value = xAttr.value('.','varchar(100)')
From XMLData.nodes('//@*') xNode(xAttr)
Where xAttr.value('local-name(.)','varchar(100)') not in ('Id','Data','Other-Columns','To-Exclude')
) C
Returns
考虑以下查询:
DECLARE @T1 TABLE(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Data] VARCHAR(100),
[Column1] VARCHAR(100),
[Column2] VARCHAR(100),
[Column3] VARCHAR(100));
INSERT INTO @T1([Data],[Column1],[Column2],[Column3])
VALUES
('Data1','C11','C21','C31'),
('Data2','C12','C22','C32'),
('Data3','C13','C23','C33'),
('Data4','C14','C24','C34'),
('Data5','C15','C25','C35');
SELECT * FROM @T1;
输出如下所示:
现在我们想要保留数据列,并且对于每个其他列,将该列的 select 的结果堆叠到最终的 table 中。换句话说,以下查询产生输出:
-- I am looking for a better solution than below!
DECLARE @output TABLE([Data] VARCHAR(100),[Column] VARCHAR(100));
INSERT INTO @output([Data],[Column])
(SELECT [Data],[Column1] FROM @T1
UNION
SELECT [Data],[Column2] FROM @T1
UNION
SELECT [Data],[Column3] FROM @T1)
SELECT * FROM @output
有什么比上述方法更清洁的方法来生成最终输出?随着列数的增加,这意味着对于每个新列,我都需要有一个单独的插入物,这似乎是一个粗略的解决方案。理想情况下,我正在寻找一个基于枢轴的解决方案,但我想不出具体的东西。
我经常使用 apply
而不是 union
:
select t1.data, t2.cols
from @t1 t1 cross apply
( values ([column1]), ([column2]), ([column3]) ) t2(cols);
当然,Yogesh 的解决方案会更高效。但是,由于您的列会随着时间的推移而扩展,这里有一种方法可以 "dynamically" 逆透视您的数据 WITHOUT 实际上使用 Dynamic SQ:
例子
Select A.[Data]
,C.*
From @T1 A
Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
Cross Apply (
Select Item = xAttr.value('local-name(.)', 'varchar(100)')
,Value = xAttr.value('.','varchar(100)')
From XMLData.nodes('//@*') xNode(xAttr)
Where xAttr.value('local-name(.)','varchar(100)') not in ('Id','Data','Other-Columns','To-Exclude')
) C
Returns