2013-04-02 70 views
9

我有下面的示例數據:SQL Server 2012的PIVOT無骨料

Id Name  Category 
----------------------- 
1  Joe  A 
2  Joe  B 
3  Joe  D 
4  Mary  A 
5  Mary  C 
6  Mary  D 

我想表明一個人屬於像現在這樣的類別:

Name CategoryA CategoryB CategoryC CategoryD 
-------------------------------------------------- 
Joe  X   X      X 
Mary  X      X   X 

1和0可以使用代替X和空格。

這對我來說就像是一個PIVOT問題。

+0

可能重複](http://stackoverflow.com/questions/12074939/get-rows-as-columns-sql-server-dynamic-pivot-query) – RichardTheKiwi

回答

25

有幾種方法可以轉換數據。一些使用聚合函數,而另一些則不使用。但即使您要旋轉字符串,您仍然可以應用聚合。

骨料與CASE:

select name, 
    max(case when category = 'A' then 'X' else '' end) CategoryA, 
    max(case when category = 'B' then 'X' else '' end) CategoryB, 
    max(case when category = 'C' then 'X' else '' end) CategoryC, 
    max(case when category = 'D' then 'X' else '' end) CategoryD 
from yourtable 
group by name 

SQL Fiddle with Demo

靜態數據透視:

你仍然可以使用PIVOT函數變換,即使值是字符串數據。如果你有一個已知數量的類別,那麼你可以硬編碼查詢:

select name, 
    coalesce(A, '') CategoryA, 
    coalesce(B, '') CategoryB, 
    coalesce(C, '') CategoryC, 
    coalesce(C, '') CategoryD 
from 
(
    select name, category, 'X' flag 
    from yourtable 
) d 
pivot 
(
    max(flag) 
    for category in (A, B, C, D) 
) piv 

SQL Fiddle with Demo

動態透視:

如果你有一個未知數量的類別,那麼你可以使用動態SQL:

DECLARE @cols AS NVARCHAR(MAX), 
    @colsNull AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX) 

select @cols = STUFF((SELECT ',' + QUOTENAME(category) 
        from yourtable 
        group by category 
        order by category 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

select @colsNull = STUFF((SELECT ', coalesce(' + QUOTENAME(category)+', '''') as '+QUOTENAME('Category'+category) 
        from yourtable 
        group by category 
        order by category 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 


set @query = 'SELECT name, ' + @colsNull + ' 
       from 
      (
       select name, category, ''X'' flag 
       from yourtable 
      ) x 
      pivot 
      (
       max(flag) 
       for category in (' + @cols + ') 
      ) p ' 

execute(@query) 

SQL Fiddle with Demo

多重連接:

select c1.name, 
    case when c1.category is not null then 'X' else '' end as CategoryA, 
    case when c2.category is not null then 'X' else '' end as CategoryB, 
    case when c3.category is not null then 'X' else '' end as CategoryC, 
    case when c4.category is not null then 'X' else '' end as CategoryD 
from yourtable c1 
left join yourtable c2 
    on c1.name = c2.name 
    and c2.category = 'B' 
left join yourtable c3 
    on c1.name = c3.name 
    and c3.category = 'C' 
left join yourtable c4 
    on c1.name = c4.name 
    and c4.category = 'D' 
where c1.category = 'A' 

SQL Fiddle with Demo

所有查詢會給結果:

| NAME | CATEGORYA | CATEGORYB | CATEGORYC | CATEGORYD | 
-------------------------------------------------------- 
| Joe |   X |   X |   |   X | 
| Mary |   X |   |   X |   X | 
的[獲取行作爲柱(SQL Server的動態PIVOT查詢)
+0

嘿......我一直在wa對答案進行編輯/細化。感謝您編輯答案,以包含我的要求,即結果包含X /空格。這符合接受的答案。 –

+2

@BlakeB。是的,它被稱爲不完全閱讀的問題,對此感到遺憾。 :) – Taryn

+0

結果表明,該解決方案的「帶CASE的聚合」版本比PIVOT解決方案的性能要好得多。 –