Transpose rows and columns with no aggregate

前端 未结 2 1425
你的背包
你的背包 2020-11-28 16:00

I have the following dataset

Account Contact

1   324324324
1   674323234
2   833343432
2   433243443
3   787655455
4   754327545
4   455435435
5   543544355         


        
2条回答
  •  攒了一身酷
    2020-11-28 16:42

    If you are going to apply the PIVOT function, you will need to use an aggregate function to get the result but you will also want to use a windowing function like row_number() to generate a unique sequence for each contact in the account.

    First, you will query your data similar to:

    select account, contact,
      'contact'
        + cast(row_number() over(partition by account
                                  order by contact) as varchar(10)) seq
    from yourtable
    

    See SQL Fiddle with Demo. This will create a new column with the unique sequence:

    | ACCOUNT |   CONTACT |      SEQ |
    |---------|-----------|----------|
    |       1 | 324324324 | contact1 |
    |       1 | 674323234 | contact2 |
    

    If you have a limited number of columns, then you could hard-code your query:

    select account,
      contact1, contact2, contact3, contact4
    from 
    (
      select account, contact,
        'contact'
          + cast(row_number() over(partition by account
                                    order by contact) as varchar(10)) seq
      from yourtable
    ) d
    pivot
    (
      max(contact)
      for seq in (contact1, contact2, contact3, contact4)
    ) piv;
    

    See SQL Fiddle with Demo

    If you have an unknown number of columns, then you will have to use dynamic SQL:

    DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)
    
    select @cols = STUFF((SELECT ',' + QUOTENAME(seq) 
                        from
                        (
                          select 'contact'
                                  + cast(row_number() over(partition by account
                                                            order by contact) as varchar(10)) seq
                          from yourtable
                        ) d
                        group by seq
                        order by seq
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    set @query = 'SELECT account, ' + @cols + ' 
                from 
                (
                    select account, contact,
                      ''contact''
                        + cast(row_number() over(partition by account
                                                  order by contact) as varchar(10)) seq
                    from yourtable
                ) x
                pivot 
                (
                    max(contact)
                    for seq in (' + @cols + ')
                ) p '
    
    execute sp_executesql @query;
    

    See SQL Fiddle with Demo. Both will give you a result of:

    | ACCOUNT |  CONTACT1 |  CONTACT2 |  CONTACT3 |  CONTACT4 |
    |---------|-----------|-----------|-----------|-----------|
    |       1 | 324324324 | 674323234 |    (null) |    (null) |
    |       2 | 433243443 | 833343432 |    (null) |    (null) |
    |       3 | 787655455 |    (null) |    (null) |    (null) |
    |       4 | 455435435 | 754327545 |    (null) |    (null) |
    |       5 | 432432432 | 432433242 | 432455553 | 543544355 |
    

提交回复
热议问题