数据的组合半转置

时间:2019-04-17 15:27:43

标签: sql sql-server tsql sql-server-2016 sql-server-2017

考虑以下查询:

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;

输出如下所示:

enter image description here

现在,我们要保留“数据”列,并将其他各列的选择结果堆叠到最终表中。换句话说,以下查询将产生输出:

-- 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

有什么比上面的方法更干净的方法来产生最终输出的呢?随着列数的增加,这意味着对于每个新列,我都需要有一个单独的插件,这似乎是一个粗略的解决方案。理想情况下,我正在寻找基于枢轴的解决方案,但我无法提出具体的建议。

enter image description here

2 个答案:

答案 0 :(得分:2)

当然,Yogesh的解决方案会更高效。但是,由于您的列会随着时间的推移而扩展,因此,以下一种方法将使用动态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

返回

enter image description here

答案 1 :(得分:1)

我经常使用apply而不是union

select t1.data, t2.cols
from @t1 t1 cross apply
     ( values ([column1]), ([column2]), ([column3]) ) t2(cols);