【问题标题】:Transposing and Expanding Columnar Dataset T-SQL转置和扩展列数据集 T-SQL
【发布时间】:2018-12-25 01:22:44
【问题描述】:

我有一个 SQL 表,类似于我在 excel 中创建的以下示例:


以下是我想要的结果。我需要将上面的数据转换成一个 2 列的列表:


以防万一需要更多信息,这是第一张图片,上面有说明我为什么使用我拥有的行的注释:

【问题讨论】:

    标签: sql sql-server database tsql transpose


    【解决方案1】:

    UnPivot 的性能当然更高,但如果您想在不实际使用 Dynamic SQL 的情况下动态取消数据透视,请考虑以下方法

    示例

    Select A.fruiteater
          ,C.*
     From  fruits A
     Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
     Cross Apply (
                    Select Item  = a.value('local-name(.)','varchar(100)')
                          ,Value = a.value('.','varchar(max)') 
                     From  B.XMLData.nodes('/row')  as C1(n)
                     Cross Apply C1.n.nodes('./@*') as C2(a)
                     Where a.value('local-name(.)','varchar(100)') not in ('fruiteater','OtherColumnsToExclude')
                 ) C
    

    退货

    fruiteater  Item    Value
    Aaron       Fruit1  Orange
    Aaron       Fruit2  Pear
    Aaron       Fruit3  Apple
    Bob         Fruit1  Apple
    Bob         Fruit2  Orange
    Bob         Fruit3  Blueberries
    Bob         Fruit4  Peach
    Bob         Fruit5  Mango
    Bob         Fruit6  Banana
    Carter      Fruit1  Pear
    Carter      Fruit2  Orange
    Carter      Fruit3  Apple
    David       Fruit1  Blueberries
    Earnest     Fruit1  Mango
    Earnest     Fruit2  Orange
    Earnest     Fruit3  Pear
    Earnest     Fruit4  Apple
    Earnest     Fruit5  Blueberries
    Frank       Fruit1  Raspberries
    

    【讨论】:

    • 哇,这里有很多我还没有接触过的东西。以下行包含了我没有看到的大部分内容:Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)。你能解释一下这条线发生了什么吗?具体回复:valuesforXML RAWFoo(XMLData)
    • @RobTruxal Cross Apply B 会将记录转换为 XML。和 Cross Apply C 将 Unpivot 数据。我是 XML 的缓慢采用者。为您的箭袋添加另一个箭头可能是值得的。 :)
    • @JohnCappelletti 。 . .我认为在这种情况下 XML 可能是矫枉过正。对于unpivot,列定义明确,因为表定义明确。 XML 的强大之处在于pivot
    • @GordonLinoff 我没有争论。我只是注意到图像中的“aka Fruit n”让我相信可变列。
    【解决方案2】:

    您可能希望使用 Unpivot 来获得预期的结果。

    create table fruits (fruiteater varchar(100), Fruit1 varchar(100), Fruit2 varchar(100), 
    Fruit3 varchar(100), Fruit4 varchar(100), Fruit5 varchar(100), Fruit6 varchar(100))  
    
    insert into fruits values ('Aaron', 'Orange', 'Pear', 'Apple', NULL, NULL, NULL) 
    ,('Bob', 'Apple', 'Orange', 'Blueberries', 'Peach', 'Mango', 'Banana') 
    ,('Carter', 'Pear', 'Orange', 'Apple', NULL, NULL, NULL) 
    ,('David', 'Blueberries', NULL, NULL, NULL, NULL, NULL) 
    ,('Earnest', 'Mango', 'Orange', 'Pear', 'Apple','Blueberries', NULL) 
    ,('Frank', 'Raspberries', NULL, NULL, NULL, NULL, NULL) 
    

    由于所有这些结果都将放在一列中,因此在进行反透视时注意数据类型和长度非常重要,因此我确保所有列都是相同的数据类型。

    select fruiteater, Value as Fruit from fruits
    unpivot 
    (value for columnname in ([Fruit1], [Fruit2], [Fruit3], [Fruit4], [Fruit5],[Fruit6]))unpvt 
    

    输出:Unpivot 将处理空值,因为它消除了它。

    fruiteater  Fruit
    Aaron   Orange
    Aaron   Pear
    Aaron   Apple
    Bob     Apple
    Bob     Orange
    Bob     Blueberries
    Bob     Peach
    Bob     Mango
    Bob     Banana
    Carter  Pear
    Carter  Orange
    Carter  Apple
    David   Blueberries
    Earnest Mango
    Earnest Orange
    Earnest Pear
    Earnest Apple
    Earnest Blueberries
    Frank   Raspberries
    

    【讨论】:

    • 特别(全面+简洁)。
    【解决方案3】:

    为此,我更喜欢横向连接 (apply)。我认为语法更简单,它不会做任何“魔术”,例如删除 NULL 值,除非您明确希望这样做:

    select f.fruiteater, v.fruit
    from fruits f cross apply
         (values (fruit1),  (fruit2),  (fruit3), (fruit4), (fruit5), (fruit6)
         ) v(fruit)
    where v.fruit is not null;
    

    更重要的是,unpivot 是一种非常具体的语法。横向连接非常灵活和强大。使用它们进行反透视是了解它们的一种非常简单的方法。

    【讨论】:

      猜你喜欢
      • 2018-08-31
      • 1970-01-01
      • 2019-09-09
      • 2011-07-28
      • 2013-05-22
      • 1970-01-01
      • 2021-02-15
      • 2017-03-31
      • 1970-01-01
      相关资源
      最近更新 更多