Search code examples
sqlsql-serversql-server-2008pivotunpivot

SQL 2008 Combining data from multiple rows with the same ID into one row


I have data in one table that contains several rows of data for the same CardNum. I would like to create a table where all the data for the same CardNum is displayed on the same row.

My data is currently like this:

PartID | CardNumber | RdrGrpID | TZID

0         412         31         1
0         412         34         1
0         567         38         1
0         567         33         5
0         567         71         3

This is how I would like the data to be:

PartID | CardNumber | RdrGrpID_1 | TZID_1 | RdrGrpID_2 | TZID_2 | RdrGrpID_3 | TZID_3

0         412         31           1        34           1
0         567         38           1        33           5        71           3

Thank you in advance.


Solution

  • To get this result, there are several ways that you can formulate the query.

    If you have a limited number of values for each partId and cardNumber, then you can use row_number() with an aggregate function/CASE combination:

    select partid, cardnumber,
      max(case when rn = 1 then rdrgrpid end) rdrgrpid_1,
      max(case when rn = 1 then TZID end) TZID_1,
      max(case when rn = 2 then rdrgrpid end) rdrgrpid_2,
      max(case when rn = 2 then TZID end) TZID_2,
      max(case when rn = 3 then rdrgrpid end) rdrgrpid_3,
      max(case when rn = 3 then TZID end) TZID_3
    from
    (
      select partId, cardNumber, RdrGrpID, TZID
          , row_number() over(partition by partiD, cardnumber
                              order by rdrgrpid) rn
      from yt
    ) d
    group by partid, cardnumber;
    

    See SQL Fiddle with Demo

    You could also use the PIVOT/UNPIVOT function to get the result:

    select *
    from
    (
      select partid, cardnumber, 
        col+'_'+cast(rn as varchar(10)) col, 
        val
      from 
      (
        select partId, cardNumber, RdrGrpID, TZID
          , row_number() over(partition by partiD, cardnumber
                              order by rdrgrpid) rn
        from yt
      ) d
      unpivot
      (
        val
        for col in (rdrgrpid, tzid)
      ) un
    ) s
    pivot
    (
      max(val)
      for col in (RdrGrpID_1, TZID_1, RdrGrpID_2, TZID_2,
                  RdrGrpID_3, TZID_3)
    ) piv
    

    See SQL Fiddle with Demo.

    Now if you have an unknown number of values, then you will need to use dynamic sql:

    DECLARE @colsPivot AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)
    
    select @colsPivot = STUFF((SELECT ',' + QUOTENAME(c.col + '_'+cast(rn as varchar(10))) 
                        from
                        (
                          select row_number() over(partition by partiD, cardnumber
                                                                        order by rdrgrpid) rn
                          from yt
                        ) t
                        cross apply
                        (
                          select 'RdrGrpID' col, 1 so union all
                          select 'TZID', 2
                        ) c
                        group by col, rn, so
                        order by rn, so
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    
    set @query 
      = 'select partid, cardnumber,  '+@colsPivot+' 
          from
          (
            select partid, cardnumber, 
              col+''_''+cast(rn as varchar(10)) col, 
              val
            from 
            (
              select partId, cardNumber, RdrGrpID, TZID
                , row_number() over(partition by partiD, cardnumber
                                    order by rdrgrpid) rn
              from yt
            ) d
            unpivot
            (
              val
              for col in (rdrgrpid, tzid)
            ) un
          ) s
          pivot
          (
            max(val)
            for col in ('+ @colspivot +')
          ) p'
    
    exec(@query);
    

    See SQL Fiddle with Demo. All versions gives the result:

    | PARTID | CARDNUMBER | RDRGRPID_1 | TZID_1 | RDRGRPID_2 | TZID_2 | RDRGRPID_3 | TZID_3 |
    -----------------------------------------------------------------------------------------
    |      0 |        412 |         31 |      1 |         34 |      1 |     (null) | (null) |
    |      0 |        567 |         33 |      5 |         38 |      1 |         71 |      3 |