Convert rows into columns by grouping one row value - sql

My table is like
CompanyName | DirectorName
ADS | Rai
ADS | Rao
ADS | Raj
ADS | Rio
SAS | Josh
SAS | John
But I want result like:
CompanyName | Director1 | Director2 | Director3 | Director4
ADS |Rai |Rao |Raj |Rio
SAS |Josh |John | |
For each company director name count varies. So kindly suggest how to form the data as per requirement dynamically.

Try this:
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
SELECT #cols = STUFF((SELECT distinct ',' +
QUOTENAME('Director' + CAST(ROW_NUMBER()
OVER(PARTITION BY c.companyname
ORDER BY c.companyname)
AS VARCHAR(10)))
FROM CompaniesDirectors c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') ,1,1,'');
SET #query = 'SELECT companyname, ' + #cols + ' from
(
SELECT
c.CompanyName,
c.DirectorName,
''Director'' + CAST(ROW_NUMBER()
OVER(PARTITION BY c.companyname
ORDER BY c.companyname)
AS VARCHAR(10)) director_num
FROM CompaniesDirectors c
) x
PIVOT
(
MAX(directorname)
FOR director_num IN (' + #cols + ')
) p ';
EXECUTE(#query);
This should give you something like:
companyname Director1 Director2 Director3 Director4
AB Foo Bar rr tt
ADS Rai Rao Raj Rio
SQL Fiddle Demo1
1: Thanks to #bluefeet

Related

Dynamic Pivot of Email Addresses

I have tried to research this, and I am unable to find something quite like it. I have a table that may have entries added many times over as well as deleted. I have no idea how many columns I will need, therefore I need a Dynamic Pivot. All the examples I see use a windows function, but I am pivoting email addresses.
The Table would look something like this:
Number | Email
--------------
1 | email1#email.com
1 | email2#email.com
1 | email3#email.com
2 | email4#email.com
2 | email5#email.com
3 | email6#email.com
4 | email7#email.com
4 | email8#email.com
I want the table to look like this(when all are included):
Number | Email1 | Email2 | Email3
---------------------------------------------------------------
1 | email1#email.com | email2#email.com | email3#email.com
2 | email4#email.com | email5#email.com |
3 | email6#email.com | |
4 | email7#email.com | email8#email.com |
If Number 1 wasn't included it would look like:
Number | Email1 | Email2
--------------------------------------------
2 | email4#email.com | email5#email.com
3 | email6#email.com |
4 | email7#email.com | email8#email.com
Thanks for the help!
Here is code to create a mock table:
CREATE TABLE #table
(number INT, email VARCHAR(30))
INSERT INTO #table (number, email)
VALUES (1,'email1#email.com')
,(1,'email2#email.com')
,(1,'email3#email.com')
,(2,'email4#email.com')
,(2,'email5#email.com')
,(3,'email6#email.com')
,(4,'email7#email.com')
,(4,'email8#email.com')
This is similar to what I have tried, I used count to try and just make it work, but was unable.
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', p.' + QUOTENAME(Number)
FROM (SELECT p.Number FROM #table AS p
GROUP BY p.Name) AS x;
SELECT #columns
SET #sql = N'
SELECT ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT p.number, p.email
FROM #test p
) AS j
PIVOT
(
Count(email) FOR Name IN ('
+ STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '')
+ ')
) AS p;';
PRINT #sql;
EXEC sp_executesql #sql;
You first need to create a RNO by partition over Number.
The following query should do what you want:
CREATE TABLE #table (Number INT, Email VARCHAR(30))
INSERT INTO #table (Number, Email)
VALUES (1,'email1#email.com')
,(1,'email2#email.com')
,(1,'email3#email.com')
,(2,'email4#email.com')
,(2,'email5#email.com')
,(3,'email6#email.com')
,(4,'email7#email.com')
,(4,'email8#email.com')
SELECT *, ROW_NUMBER() OVER (PARTITION BY Number ORDER BY Number, Email) AS [RNO] INTO #temp FROM #table
DECLARE #DynamicCols NVARCHAR(MAX) = '';
DECLARE #pvt NVARCHAR(MAX) = '';
SET #pvt = STUFF(
(SELECT DISTINCT N', ' + QUOTENAME([RNO]) FROM #temp FOR XML PATH('')),1,2,N'')
SET #DynamicCols = STUFF(
(SELECT DISTINCT N', ' + QUOTENAME([RNO]) + ' AS '+ QUOTENAME('Email' + CAST([RNO] AS VARCHAR(MAX))) FROM #temp FOR XML PATH('')),1,2,N'')
EXEC (N'SELECT [Number],'+ #DynamicCols+'
FROM #temp tmp
PIVOT (MAX([Email]) FOR RNO IN('+#pvt+')) AS PIV');

Dynamic sql pivot values coming in seperate columns

HI I am trying to write dynamic pivot as I have over 100 columns
ID Question Answer
1 Name peter
1 DOB 11/12/2003
1 address …..
1 Issue1 d
1 Issue2 a
2 Name sam
2 DOB 10/01/1998
2 address …..
2 Issue1 p
2 Issue2 f
I want the output like this:
ID Name DOB address Issue1 Issue2
1 peter 11/12/2003 …. d a
2 sam 10/01/1998 …. p f
Here is the code that I have used:-
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(Question)
from #temp
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ID + #cols + N'
from #temp
pivot
(
max([answer])
for Question in (' + #cols + N')
) p '
exec sp_executesql #query;
But I am getting each answer in a separate row. I want all the answers of an ID to come in one row. Can somebody help me. Appreciate your time on this. Thank you.
I am getting the output like this, which is not I want. I want the output as above.
ID Name DOB address Issue1 Issue2
1 Peter
1 11/12/2003
1 …
1 d
1 a
It looks like you are looking for a way to dynamically create a pivot based on your table without aggregation. You can try the following:
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(Question)
FROM #TEMP
GROUP BY QUESTION
ORDER BY QUESTION
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ID,' + #cols + ' FROM
(
SELECT ID, Question, Answer
FROM #TEMP
) x
pivot
(
MAX(Answer)
for Question in (' + #cols + ')
) p '
execute(#query);
Expected Output:
+----+---------+------------+--------+--------+-------+
| ID | address | DOB | Issue1 | Issue2 | Name |
+----+---------+------------+--------+--------+-------+
| 1 | ….. | 11/12/2003 | d | a | peter |
| 2 | ….. | 10/1/1998 | p | f | sam |
+----+---------+------------+--------+--------+-------+

Convert Decimal to String on Pivot

example Code
Declare
#table1 VARCHAR(MAX)
Set #table1 = 'Select * from #tempTbl'
Declare
#List VARCHAR(MAX),
#Pivot VARCHAR(MAX)
Select #List = ISNULL(#List + ',', '') + TrxCd From TransacMaster Where Module = 'CB'
Set #Pivot = '
SELECT ROW_NUMBER() OVER (ORDER BY DebtorCd ASC) As RowIndex, *
FROM (
Select Distinct
c.UserId,
d.Name,
b.TrxCd
SUM(b.Amount) As Amount
From tbl_InvH a
Inner Join tbl_InvD b on a.subCd = b.subCd and a.InvNo = b.InvNo
Left Join tbl_User c On a.UserId = c.UserId
Left Join tbl_Personnel d on c.PersonnelId = d.PersonnelId
Group By c.UserId, d.Name, b.TrxCd
) as s
PIVOT
(
SUM(Amount)
FOR TrxCd IN (' + #List + ')
)AS pvt'
Declare #Result nVarchar(MAX)
Set #Result = #table1 + '
Union All
' + #Pivot
Exec sp_executesql #Result
I want to Convert Field Amount from decimal to String, because after this I want to UNION with another tables, but field amount and field from another table is different type.
I have tried CAST(SUM(Amount) as Varchar) But Error :
'CAST' is not a recognized aggregate function.
I can't Convert on Main Select because Field of TrxCd is Dynamic
Result Of Pivot
RowIndex | UserId | Name | IT01 | IT02 | IT03 | IT04
--------------------------------------------------------------------------------
1 | John | John Ivy | 2,000 | 2,000 | 1,000 | 5,000
2 | Merry | Merry Ish | 1,000 | 1,000 | 1,000 | 6,000
other Table
RowIndex | UserId | Name | Transac1 | Transac2 | Transac3 | Transac4
-------------------------------------------------------------------------------------------------
1 | John | John Ivy | Trx Bank A | Trx Bank B | Trx Bank C | Trx Bank D
What should I do to Convert Field Amount from Pivot.
Because of the dynamic nature, you could take the same #List expression Select #List = ISNULL(#List + ',', '') + TrxCd From TransacMaster Where Module = 'CB' and create a second for the dynamic casting in the main select;
Select #List2 = ISNULL(#List2 + ',', '') + 'cast(' + TrxCd + 'as varchar)' From TransacMaster Where Module = 'CB'
Then use this and additional columns required to replace the asterix in the main select;
'SELECT ROW_NUMBER() OVER (ORDER BY DebtorCd ASC) As RowIndex, UserId, Name,' + #List2 +'....'

Transforming a column in rows [duplicate]

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
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

Dynamic Pivot Columns in SQL Server

I have a table named Property with following columns in SQL Server:
Id Name
There are some property in this table that certain object in other table should give value to it.
Id Object_Id Property_Id Value
I want to make a pivot table like below that has one column for each property I've declared in 1'st table:
Object_Id Property1 Property2 Property3 ...
I want to know how can I get columns of pivot dynamically from table. Because the rows in 1'st table will change.
Something like this:
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' +
QUOTENAME(Name)
FROM property
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SELECT #query =
'SELECT *
FROM
(
SELECT
o.object_id,
p.Name,
o.value
FROM propertyObjects AS o
INNER JOIN property AS p ON o.Property_Id = p.Id
) AS t
PIVOT
(
MAX(value)
FOR Name IN( ' + #cols + ' )' +
' ) AS p ; ';
execute(#query);
SQL Fiddle Demo.
This will give you something like this:
| OBJECT_ID | PROPERTY1 | PROPERTY2 | PROPERTY3 | PROPERTY4 |
-------------------------------------------------------------
| 1 | ee | fd | fdf | ewre |
| 2 | dsd | sss | dfew | dff |