I have the following dataset
Account Contact
1   324324324
1   674323234
2   833343432
2   433243443
3   787655455
4   754327545
4   455435435
5   543544355
5   432455553
5   432433242
5   432432432
I'd like output as follows:
Account Contact1    Contact2    Contact3    Contact4
1   324324324   674323234       
2   833343432   433243443       
3   787655455           
4   754327545   455435435       
5   543544355   432455553   432433242   432432432
The problem is also that I have an unfixed amount of Accounts & unfixed amount of Contacts
The answer is no: PIVOT requires aggregation.
The 1st table (Table) holds tables name. The 2nd table (Fields) is related to (Table) to hold the fields name for each table. The 3rd table (Field Value) is related to (Fields) to hold fields value for each field.
GROUP BY without Aggregate Functions Although most of the times GROUP BY is used along with aggregate functions, it can still still used without aggregate functions — to find unique records.
There is no any way to PIVOT without aggregating. Save this answer. Show activity on this post.
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 |
                        Just a slightly different way to generate the dynamic PIVOT:
DECLARE @c INT;
SELECT TOP 1 @c = COUNT(*) 
  FROM dbo.YourTable
  GROUP BY Account 
  ORDER BY COUNT(*) DESC;
DECLARE @dc1 NVARCHAR(MAX) = N'', @dc2 NVARCHAR(MAX) = N'', @sql NVARCHAR(MAX);
SELECT @dc1 += ',Contact' + RTRIM(i), @dc2 += ',[Contact' + RTRIM(i) + ']'
  FROM (SELECT TOP (@c) i = number + 1 
  FROM master.dbo.spt_values WHERE type = N'P' ORDER BY number) AS x;
SET @sql = N'SELECT Account ' + @dc1 + 
  ' FROM (SELECT Account, Contact, rn = ''Contact'' 
      + RTRIM(ROW_NUMBER() OVER (PARTITION BY Account ORDER BY Contact))
    FROM dbo.YourTable) AS src PIVOT (MAX(Contact) FOR rn IN (' 
      + STUFF(@dc2, 1, 1, '') + ')) AS p;';
EXEC sp_executesql @sql;
SQLiddle demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With