-2

I have data in a SQLServer table like this:

ID   Name   Year   Value
--   ----   ----   -----
2    Ted    2013   2000
2    Ted    2012   1000

I need the view syntax to output this:

ID    Name    Yr1    Value1    Yr2    Value2
--    ----    ---    ------    ---    ------ 
2     Ted     2013   2000      2012   1000

No cursors if possible. Any clues would be greatful.

Taryn
  • 242,637
  • 56
  • 362
  • 405
kanderson
  • 5
  • 5
  • 1
    May be helpful: [Using PIVOT and UNPIVOT](http://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx) –  Aug 26 '13 at 22:24
  • Are you going to be limited to two years in your result? – Taryn Aug 26 '13 at 22:35

1 Answers1

3

In SQL Server there are several ways that you can get the result.

If you have a limited number of values, then you can easily hard-code the result. One way you can get the result would be using an aggregate function with a CASE expression:

select d.id,
  d.name,
  max(case when seq = 1 then year end) year1,
  max(case when seq = 1 then value end) value1,
  max(case when seq = 2 then year end) year2,
  max(case when seq = 2 then value end) value2
from
(
  select id, name, year, value,
    row_number() over(partition by id order by year desc) seq
  from yourtable
) d
group by d.id, d.name;

See SQL Fiddle with Demo. If you want to use the PIVOT function, then I would suggest first unpivoting the data in the year and value columns first. The process of unpivot converts the multiple columns into multiple rows. You can use the UNPIVOT function, but in my example I used CROSS APPLY with a UNION ALL query and the code is:

select t.id, t.name, 
  col = c.col+cast(seq as varchar(4)), 
  c.val
from
(
  select id, name, year, value,
    row_number() over(partition by id order by year desc) seq
  from yourtable
) t
cross apply
(
  select 'year', t.year union all
  select 'value', t.value 
) c (col, val)

See SQL Fiddle with Demo. This converts your multiple columns into a slightly different format with multiple rows:

| ID | NAME |    COL |  VAL |
|  2 |  Ted |  year1 | 2013 |
|  2 |  Ted | value1 | 2000 |
|  2 |  Ted |  year2 | 2012 |
|  2 |  Ted | value2 | 1000 |

You can then apply the PIVOT function on this to get your final desired result:

select id, name, year1, value1, year2, value2
from 
(
  select t.id, t.name, 
    col = c.col+cast(seq as varchar(4)), 
    c.val
  from
  (
    select id, name, year, value,
      row_number() over(partition by id order by year desc) seq
    from yourtable
  ) t
  cross apply
  (
    select 'year', t.year union all
    select 'value', t.value 
  ) c (col, val)
) d
pivot
(
  max(val)
  for col in (year1, value1, year2, value2)
) piv;

See SQL Fiddle with Demo. Finally if you have an unknown number of values that you want to transform from rows into columns, then you can use dynamic SQL inside a stored procedure:

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

select @cols = STUFF((SELECT  ',' + QUOTENAME(col+cast(seq as varchar(4))) 
                    from 
                    (
                      select row_number() over(partition by id order by year desc) seq
                      from yourtable
                    ) d
                    cross apply 
                    (
                      select 'year', 1 union all
                      select 'value', 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 id, name,' + @cols + ' 
             from 
             (
               select t.id, t.name, 
                  col = c.col+cast(seq as varchar(4)), 
                  c.val
                from
                (
                  select id, name, year, value,
                    row_number() over(partition by id order by year desc) seq
                  from yourtable
                ) t
                cross apply
                (
                  select ''year'', t.year union all
                  select ''value'', t.value 
                ) c (col, val)
            ) x
            pivot 
            (
                max(val)
                for col in (' + @cols + ')
            ) p '

execute sp_executesql @query;

See SQL Fiddle with Demo. All versions will give a result:

| ID | NAME | YEAR1 | VALUE1 | YEAR2 | VALUE2 |
|  2 |  Ted |  2013 |   2000 |  2012 |   1000 |
Taryn
  • 242,637
  • 56
  • 362
  • 405