Question

I am trying to use a pivot to get information in a diff format.

Here is my table:

    CREATE TABLE yourtable
([case] int, [category] varchar(4))
    ;

    INSERT INTO yourtable
([case], [category])
    VALUES
(1, 'xx'),
(1, 'xyx'),
(1, 'abc'),
(2, 'ghj'),
(2, 'asdf'),
(3, 'dfgh')
    ; 

Here is my pivot command courtesy of bluefeet:

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

    select @cols = STUFF((SELECT distinct ',' + QUOTENAME('cat'+cast(seq as    
    varchar(10))) 
                from
                (
                  select row_number() over(partition by [case] 
                                           order by category) seq
                  from yourtable
                ) d
        FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')

    set @query = 'SELECT [case],' + @cols + ' 
        from 
        (
          SELECT [case], category,
            ''cat''+
              cast(row_number() over(partition by [case] 
                                     order by category) as varchar(10)) seq
          FROM yourTable
        ) x
        pivot 
        (
            max(category)
            for seq in (' + @cols + ')
        ) p '

    execute sp_executesql @query;

The output is good, it is in the format I need.

CASE    CAT1    CAT2    CAT3
1        abc    xx    xyx
2        asdf   ghj   (null)
3        dfgh   (null)   (null)

However, I also need to add additional columns to the table. The modified table would be as follows, but I'm not sure how to add this to the QUOTENAME.

    CREATE TABLE yourtable
    ([case] int, [category] varchar(4), [status] varchar(4))
    ;

    INSERT INTO yourtable
    ([case], [category], [status])
    VALUES
    (1, 'xx', '00'),
    (1, 'xyx', '01'),
    (1, 'abc', '00'),
    (2, 'ghj', '01'),
    (2, 'asdf', '00'),
    (3, 'dfgh', '01')
     ; 

How can this be done? Should I add an additional QUOTENAME command? Results should be:

    CASE    CAT1    status1    CAT2      status2      CAT3      status3
    1       abc     00         xx          00         xyx        01
    2       asdf    00         ghj         01       (null)    (null)
    3       dfgh    01        (null)     (null)     (null)    (null)
Was it helpful?

Solution

Since you now have two columns that you want to PIVOT, you can first unpivot the category and status columns into a single column with multiple rows.

There are a few different ways you can unpivot the data, you can use UNPIVOT or CROSS APPLY. The basic syntax will be:

select [case],
  col+cast(seq as varchar(10)) seq,
  value
from
(
  SELECT [case], status, category,
    row_number() over(partition by [case] 
                      order by status) seq
  FROM yourTable
) d
cross apply
(
  select 'cat', category union all
  select 'status', status
) c (col, value)

See SQL Fiddle with Demo This will convert your multiple columns of data into something that looks like this:

| CASE |     SEQ | VALUE |
|------|---------|-------|
|    1 |    cat1 |    xx |
|    1 | status1 |    00 |
|    1 |    cat2 |   abc |
|    1 | status2 |    00 |
|    1 |    cat3 |   xyx |
|    1 | status3 |    01 |
|    2 |    cat1 |  asdf |
|    2 | status1 |    00 |

Once the data is in this format, then you can apply the PIVOT function to it.

SELECT [case], cat1, status1, cat2, status2, cat3, status3
FROM
(
  select [case],
    col+cast(seq as varchar(10)) seq,
    value
  from
  (
    SELECT [case], status, category,
      row_number() over(partition by [case] 
                        order by status) seq
    FROM yourTable
  ) d
  cross apply
  (
    select 'cat', category union all
    select 'status', status
  ) c (col, value)
) x
PIVOT
(
   max(value)
   for seq in (cat1, status1, cat2, status2, cat3, status3)
)p;

See SQL Fiddle with Demo

Then you can convert it to dynamic SQL:

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

select @cols = STUFF((SELECT  ',' + QUOTENAME(col+cast(seq as varchar(10))) 
                    from
                    (
                      select row_number() over(partition by [case] 
                                               order by category) seq
                      from yourtable
                    ) d
                    cross apply
                    (
                      select 'cat', 1 union all
                      select 'status', 2 
                    ) c (col, so)
                    group by seq, col, so
                    order by seq, so
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT [case],' + @cols + ' 
            from 
            (
              select [case],
                col+cast(seq as varchar(10)) seq,
                value
              from
              (
                SELECT [case], status, category,
                  row_number() over(partition by [case] 
                                    order by status) seq
                FROM yourTable
              ) d
              cross apply
              (
                select ''cat'', category union all
                select ''status'', status
              ) c (col, value)
            ) x
            pivot 
            (
                max(value)
                for seq in (' + @cols + ')
            ) p '

execute sp_executesql @query;

See SQL Fiddle with Demo The final result will be:

| CASE | CAT1 | STATUS1 |   CAT2 | STATUS2 |   CAT3 | STATUS3 |
|------|------|---------|--------|---------|--------|---------|
|    1 |   xx |      00 |    abc |      00 |    xyx |      01 |
|    2 | asdf |      00 |    ghj |      01 | (null) |  (null) |
|    3 | dfgh |      01 | (null) |  (null) | (null) |  (null) |
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top