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