SQL Server 2012 PIVOT without aggregate

后端 未结 1 734
迷失自我
迷失自我 2021-01-04 10:40

I have the following sample data:

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


        
1条回答
  •  礼貌的吻别
    2021-01-04 10:58

    There are several ways that you can transform the data. Some use an aggregate function and others don't. But even though you are pivoting a string you can still apply an aggregate.

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

    See SQL Fiddle with Demo

    Static Pivot:

    You can still use the PIVOT function to transform the data even though the values are strings. If you have a known number of categories, then you can hard-code the query:

    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
    

    See SQL Fiddle with Demo.

    Dynamic Pivot:

    If you have an unknown number of categories, then you can use dynamic 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)
    

    See SQL Fiddle with Demo.

    Multiple Joins:

    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'
    

    See SQL Fiddle with Demo

    All queries will give the result:

    | NAME | CATEGORYA | CATEGORYB | CATEGORYC | CATEGORYD |
    --------------------------------------------------------
    |  Joe |         X |         X |           |         X |
    | Mary |         X |           |         X |         X |
    

    0 讨论(0)
提交回复
热议问题