什么是透视这些数据的好方法?

时间:2019-05-24 14:22:06

标签: sql sql-server

我具有以下粒度的数据:

CityID | Name | Post_Science | Post_Science | Post_Reading | Pre_Reading | Post_Writing | Pre_Writing  
123    | Bob  | 2.0          | 1.0          |     2.0      |    4.0      |     1.0      | 1.0

我将这些<Post/Pre>_XXXXXX列称为“标签”。基本上,这些没有“前”或“后”文本的列名称都映射到另一个表中的标签。

我想以某种方式透视数据,以便对于pre的每组,相同Label的postCityID, Name, Label值位于同一行。所以看起来像这样:

CityID | Name | Pre Category | Post Category | Label 
123    | Bob  | 1.0          |     2.0       | Science
123    | Bob  | 4.0          |     2.0       | Reading
123    | Bob  | 1.0          |     1.0       | Writing

Label通过联接来自单独的表。希望这不会混淆任何人。如果是这样,请暂时忽略该列。

因此,这些类别中有更多类别-例如,科学,阅读和写作只是我所选择的几个类别。

我想到了两种方法来获取这种格式的数据:

  1. 将所有数据取消透视成一组CityID, Name, Label中所有值的长列表。然后解析Label名称,然后将其转到一类的前值和后值分成1行
  2. 做一堆Union。因此,在一个select语句中选择所有科学,在另一个select语句中选择所有Reading,然后将它们合并。大约有50个配对,所以有50个并集语句

我在想第一个选项比后者更干净。还有其他选择吗?

2 个答案:

答案 0 :(得分:2)

这是不可更改,我强烈建议apply

select t.CityId, t.Name, v.*
from t cross apply
     (values (t.Post_Science, t.Pre_Science, 'Science'),
             (t.Post_Reading, t.Pre_Reading, 'Reading'),
             (t.Post_Writing, t.Pre_Writing, 'Writing')
     ) v(postcategory, precategory, label) ;

UNPIVOT是做一件事的非常特殊的语法。 APPLY引入了横向连接,横向连接对于此目的和许多其他目的非常有用。

答案 1 :(得分:1)

很明显,戈登的解决方案性能更高,但是如果您有很多或可变的列,则此选项可以动态取消对数据的使用,而无需实际使用DYNAMIC SQL

示例

Select A.CityID
      ,A.Name
      ,PreCat  = max(case when Item Like 'Pre%'  then Value end)
      ,PostCat = max(case when Item Like 'Post%' then Value end)
      ,Label   = substring(Item,charindex('_',Item+'_')+1,50)
 From  YourTable 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(max)')
                 From  XMLData.nodes('//@*') xNode(xAttr)
                 Where xAttr.value('local-name(.)','varchar(100)') not in ('CityId','Name','Other-Columns','To-Exclude')
             ) C
 Group By A.CityID
         ,A.Name
         ,substring(Item,charindex('_',Item+'_')+1,50)

返回

CityID  Name    PreCat  PostCat Label
123     Bob     4.0     2.0     Reading
123     Bob     1.0     2.0     Science
123     Bob     1.0     1.0     Writing