SQL: Putting an individuals distinct diagnosis into one horizontal row - sql

I'm using Microsoft SQL Server 2008 for a mental health organization.
I have a table that lists all of out clients and their diagnoses, but each diagnoses that a client has is in a new row. I want them all to be in a single row listed out horizontally with the date for each diagnosis. Some people have just one diagnosis, some have 20, some have none.
Here's an example of how my data sort of looks now (only with a lot few clients, we have thousands):
And Here's the format I'd like it to end up:
Any solutions you could offer or hints in the right direction would be great, thanks!

In order to get the result, I would first unpivot and then pivot your data. The unpivot will take your date and diagnosis columns and convert them into rows. Once the data is in rows, then you can apply the pivot.
If you have a known number of values, then you can hard-code your query similar to this:
select *
from
(
select person, [case#], age,
col+'_'+cast(rn as varchar(10)) col,
value
from
(
select person,
[case#],
age,
diagnosis,
convert(varchar(10), diagnosisdate, 101) diagnosisDate,
row_number() over(partition by person, [case#]
order by DiagnosisDate) rn
from yourtable
) d
cross apply
(
values ('diagnosis', diagnosis), ('diagnosisDate', diagnosisDate)
) c (col, value)
) t
pivot
(
max(value)
for col in (diagnosis_1, diagnosisDate_1,
diagnosis_2, diagnosisDate_2,
diagnosis_3, diagnosisDate_3,
diagnosis_4, diagnosisDate_4)
) piv;
See SQL Fiddle with Demo.
I am going to assume that you will have an unknown number of diagnosis values for each case. If that is the case, then you will need to use dynamic sql to generate the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(col+'_'+cast(rn as varchar(10)))
from
(
select row_number() over(partition by person, [case#]
order by DiagnosisDate) rn
from yourtable
) t
cross join
(
select 'Diagnosis' col union all
select 'DiagnosisDate'
) c
group by col, rn
order by rn, col
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT person,
[case#],
age,' + #cols + '
from
(
select person, [case#], age,
col+''_''+cast(rn as varchar(10)) col,
value
from
(
select person,
[case#],
age,
diagnosis,
convert(varchar(10), diagnosisdate, 101) diagnosisDate,
row_number() over(partition by person, [case#]
order by DiagnosisDate) rn
from yourtable
) d
cross apply
(
values (''diagnosis'', diagnosis), (''diagnosisDate'', diagnosisDate)
) c (col, value)
) t
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute(#query);
See SQL Fiddle with Demo. Both queries give the result:
| PERSON | CASE# | AGE | DIAGNOSIS_1 | DIAGNOSISDATE_1 | DIAGNOSIS_2 | DIAGNOSISDATE_2 | DIAGNOSIS_3 | DIAGNOSISDATE_3 | DIAGNOSIS_4 | DIAGNOSISDATE_4 |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| John | 13784 | 56 | Depression | 03/13/2012 | Brain Injury | 03/14/2012 | Spinal Cord Injury | 03/15/2012 | Hypertension | 03/16/2012 |
| Kate | 2643 | 37 | Bipolar | 03/11/2012 | Hypertension | 03/12/2012 | (null) | (null) | (null) | (null) |
| Kevin | 500934 | 25 | Down Syndrome | 03/18/2012 | Clinical Obesity | 03/19/2012 | (null) | (null) | (null) | (null) |
| Pete | 803342 | 34 | Schizophenia | 03/17/2012 | (null) | (null) | (null) | (null) | (null) | (null) |

For this type of pivoting, I think the aggregate/group method is feasible:
select d.case, d.person,
max(case when seqnum = 1 then diagnosis end) as d1,
max(case when seqnum = 1 then diagnosisdate end) as d1date,
max(case when seqnum = 2 then diagnosis end) as d2,
max(case when seqnum = 2 then diagnosisdate end) as d2date,
. . . -- and so on, for as many groups that you want
from (select d.*, row_number() over (partition by case order by diagnosisdate) as seqnum
from diagnoses d
) d
group by d.case, d.person

Since you are dealing with sensitive medical information, identifyiable information (name age etc) shouldn't be stored in the same table as the medical information. Also, if you extract out the person info into its own table and a Diagnosis table that has the personID foreign key you can establish the 1 to many relationship you want.

Unless you use Dynamic SQL, the PIVOT operator will not work here. I assume that patients can come in on any date. The PIVOT operator works with a finite and predefined number of columns. Your options are to use Dynamic SQL to create the PIVOT table, or to use Excel or a reporting tool like SSRS to do a Pivot report.
I think the Dynamic SQL option would not be practical here, since, you could end up having hundreds of columns for each of the patient visit dates.
If you want to explore the Dynamic SQL option anyway, have a look here:
https://www.simple-talk.com/blogs/2007/09/14/pivots-with-dynamic-columns-in-sql-server-2005/

Related

Extract the maximum value from the last number in a hierarchyID?

I have a column with hierarchy IDs converted to strings in SQL Server. I need to add new hierarcyIDs for the new lines, but first I have to find the last child of the current ID. The hierarchyIDs are look like these:
/1/1/1/6/1/
/1/1/1/6/7/
/1/1/1/6/3/
/1/1/1/6/13/
/1/1/1/6/4/
As you can see, the maximum number is not equal with the count of the lines, so I can not use count()+1 unfortunately.
What I need to extract from this list is:
13
I only have experience in PL SQL, where it was easy to do this with regexp functions, but I can not find the solution in SQL Server.
You can use some STRING operation as below to get your desired output-
DEMO HERE
WITH your_table(your_column)
AS
(
SELECT '/1/1/1/6/1/' UNION ALL
SELECT '/1/1/1/6/7/' UNION ALL
SELECT '/1/1/1/6/3/' UNION ALL
SELECT '/1/1/1/6/13/' UNION ALL
SELECT '/1/1/1/6/4/'
)
SELECT
MAX(
CAST(
REVERSE(
LEFT(
REVERSE(LEFT(your_column,LEN(your_column)-1)),
CHARINDEX('/',REVERSE(LEFT(your_column,LEN(your_column)-1)) ,0) - 1
)
)
AS INT
)
)
FROM your_table
Note: Data has to be as your sample data
The creators of hierarchyid have anticipated your needs and have an officially supported solution for this.
declare #h table (h HIERARCHYID);
insert into #h (h)
values
('/1/1/1/6/1/'),
('/1/1/1/6/7/'),
('/1/1/1/6/3/'),
('/1/1/1/6/13/'),
('/1/1/1/6/4/');
declare #parent HIERARCHYID = '/1/1/1/6/';
declare #maxChild HIERARCHYID = (
select max(h)
from #h
where h.IsDescendantOf(#parent) = 1
);
-- ToString() added here for readability in the output;
-- it's not needed to be used as data.
select #parent.GetDescendant(#maxChild, null).ToString();
You can read more about this here.
Another way around this is to specify your own components to the hierarchyid yourself. I like to use the primary key values. For example, let's say that this data represents a company's org chart. If EmployeeID 1 is the CEO, 42 is the CFO (who reports to the CEO) and 306 is Accounting Manager (who reports to the CFO), the latter's hierarchyid would be /1/42/306/. Because the PK values are unique, the generated hierarchid is also unique.
To give some ideas, 2 solutions.
The first one is for Sql Server 2017 and beyond.
The second for most versions below that.
create table YourTable
(
ID int identity(101,1) primary key,
hierarcyIDs varchar(100)
)
GO
✓
insert into YourTable
(hierarcyIDs) values
('/1/2/3/4/5/')
,('/1/2/3/4/15/')
,('/1/2/3/4/10/')
,('/11/12/13/14/15/')
,('/11/12/13/14/42/')
;
GO
5 rows affected
SELECT
[1] as id1,
[2] as id2,
[3] as id3,
[4] as id4,
max([5]) as id5,
concat_ws('/','',[1],[2],[3],[4],max([5])+1,'') as nextHierarcyIDs
FROM YourTable
OUTER APPLY
(
select *
from
( select try_cast(value as int) as id
, row_number() over (order by (select 0)) rn
from string_split(trim('/' from hierarcyIDs),'/') s
) src
pivot (max(id)
for rn in ([1],[2],[3],[4],[5])
) pvt
) anarchy
group by [1],[2],[3],[4]
GO
id1 | id2 | id3 | id4 | id5 | nextHierarcyIDs
--: | --: | --: | --: | --: | :---------------
1 | 2 | 3 | 4 | 15 | /1/2/3/4/16/
11 | 12 | 13 | 14 | 42 | /11/12/13/14/43/
SELECT hierarcyIdLvl1to4
, MAX(hierarcyIDLvl5) AS maxHierarcyIDLvl5
FROM
(
SELECT id, hierarcyIDs
, substring(hierarcyIDs, 0, len(hierarcyIDs)-charindex('/',
reverse(hierarcyIDs),2)+2) AS hierarcyIdLvl1to4
, reverse(substring(reverse(hierarcyIDs),2,charindex('/',
reverse(hierarcyIDs),2)-2)) AS hierarcyIDLvl5
FROM YourTable
) q
GROUP BY hierarcyIdLvl1to4
GO
hierarcyIdLvl1to4 | maxHierarcyIDLvl5
:---------------- | :----------------
/1/2/3/4/ | 5
/11/12/13/14/ | 42
db<>fiddle here

Reverse col and rows in SQL

I have to create query, to reverse rows and cols correct. I am using MS SQL SERVER 2016.
This is what I have:
Row_ID | Group_ID | Group_Status | MemberRole | name
2807 | 10568 | accept | chairman | Rajah
2808 | 10568 | accept | member | Vaughan
2812 | 10568 | accept | secretary | Susan
This is what I need:
Group_ID | Status | Chairman | Secretary | Member1 | Member2 | Member3 | ... | Member20
10568 | Accept | Rajah | Susan | Vaughan | Kane | Oprah | ... | Imelda
(users with member role can be between 0-20)
Probably I should use pivot, but I have no idea how.
Ok, I have this code:
SELECT *
FROM
(
SELECT group_id,
group_status,
memberRole,
name
FROM DataGroup
) dataSource PIVOT(MAX(name) FOR memberRole IN([chairman],
[secretary],
[member])) pivotTab;
But I losing rows with members (get only one member), how to extract them to columns?
You can try this with a unioned query:
Some mockup (please provide such a dummy table with your sample data yourself in your next question):
DECLARE #mockup TABLE(Row_ID INT,Group_ID INT,Group_Status VARCHAR(100),MemberRole VARCHAR(100),[name] VARCHAR(100));
INSERT INTO #mockup VALUES
(2807,10568,'accept','chairman','Rajah')
,(2808,10568,'accept','member','Vaughan')
,(2812,10568,'accept','secretary','Susan')
,(2899,10568,'accept','member','Onemore');
--The query
SELECT p.*
FROM
(
SELECT Group_ID
,Group_Status
,[name]
,MemberRole
FROM #mockup
WHERE MemberRole IN('chairman','secretary')
UNION ALL
SELECT Group_ID
,Group_Status
,[name]
,CONCAT('Member',ROW_NUMBER() OVER(PARTITION BY Group_ID ORDER BY Row_ID))
FROM #mockup
WHERE MemberRole='member'
) t
PIVOT
(
MAX([name]) FOR MemberRole IN(Chairman,Secretary,Member1,Member2,Member3 /*add as many as you need*/)
) p;
The result
Group_ID Group_Status Chairman Secretary Member1 Member2 Member3
10568 accept Rajah Susan Vaughan Onemore NULL
In short:
The first part of the query will Just pick the two fix names.
The second part will pick the members and number them sorted by their Row_ID.
The PIVOT will then transform this to a single row, using the column MemberRole for the new column names.
You will have to think about some more things:
What if not all the lines are accepted?
What of there are many groups?
If you need help, you can comeback with a new question. Happy Coding!
I would simply use conditional aggregation:
select group_id, group_status,
max(case when member_role = 'chairman' then name end) as chairman,
max(case when member_role = 'secretary' then name end) as secretary,
max(case when member_role = 'member' and seqnum = 1 then name end) as member_01,
max(case when member_role = 'member' and seqnum = 2 then name end) as member_02,
. . .
from (select m.*,
row_number() over (partition by group_id, member_role order by row_id) as seqnum
from #mockup m
) m
group by group_id, group_status;
I find conditional aggregation to be much more flexible than pivot. This is an example of the situation where the query is simpler.

transform rows into one row based on unique ID

Reason | ID
---------------------------------------
Sales - Agent Attitude | 2
---------------------------------------
Billing - Process | 2
---------------------------------------
Technical - Outages | 1005
---------------------------------------
Technical - knowledge | 1005
---------------------------------------
Others | 1005
---------------------------------------
i have the above table and i want a result like the below by using SQL server i can combine rows into one row by separating them by , by using STUFF() function but i want the format as the below so any help
ID | Reason 1 | Reason 2 | Reason 3
---------------------------------------------------------------------
2 | Sales - Agent Attitude | Billing - Process | NULL
---------------------------------------------------------------------
1005 | Technical - Outages | Technical - knowledge |Others
---------------------------------------------------------------------
Try below query..
select distinct
ID , [1] as 'Reason 1' , [2] as 'Reason 2' , [3] as 'Reason 3'
from
(
select *, ROW_NUMBER() OVER ( PARTITION BY id ORDER BY reason DESC ) as RID from #temp
) src
pivot
(
max(Reason)
for rid in ([1], [2],[3])
) piv
plz let us know if you have any que. or concerns
This is the pivot solution:
;with
t as (
SELECT 'Reason ' + cast(ROW_NUMBER() over (partition by id order by id) as varchar(2)) n, *
from YourTable
)
select *
FROM t
pivot (min(reason) for n in ([Reason 1],[Reason 2],[Reason 3],[Reason 4],[Reason 5])) p

How to transform records data into columns

Please find the sample data:
h_company_id company_nm mainphone1 phone_cnt
20816 800 Flowers 5162377000 3
20816 800 Flowers 5162377131 1
20820 1st Source Corp. 5742353000 3
20821 1st United Bancorp 5613633400 2
20824 3D Systems Inc. 8033273900 4
20824 3D Systems Inc. 8033464010 1
11043 3I Group PLC 2079757115 1
11043 3I Group PLC 2079753731 15
Desired Output:
h_company_id company_nm mainphone1 phone_cnt mainphone2 phone_cnt2
20816 800 Flowers 5162377000 3 5162377131 1
20820 1st Source Corp. 5742353000 3 NULL NULL
20821 1st United Bancorp 5613633400 2 NULL NULL
20824 3D Systems Inc. 8033273900 4 8033464010 1
11043 3I Group PLC 2079757115 1 2079753731 15
(copy above in notepad/excel)
Hi Guys,
I want to transpose records of columns mainphone1 and phone_cnt as new columns namely mainphone2, phone_cnt2 so that the data in column h_company_id should be unique means there should be only single entry of h_company_id.
Thanks in advance!
Transforming from rows into columns is called a PIVOT and there are several different ways that this can be done in SQL Server.
Aggregate / CASE: You can use an aggregate function along with a CASE expression. This will work by applying the row_number() windowing function to the data in your table:
select h_company_id, company_nm,
max(case when seq = 1 then mainphone1 end) mainphone1,
max(case when seq = 1 then phone_cnt end) phone_cnt1,
max(case when seq = 2 then mainphone1 end) mainphone2,
max(case when seq = 2 then phone_cnt end) phone_cnt2
from
(
select h_company_id, company_nm, mainphone1, phone_cnt,
row_number() over(partition by h_company_id order by mainphone1) seq
from yourtable
) d
group by h_company_id, company_nm;
See SQL Fiddle with Demo. The CASE expression checks if the sequence number has the value 1 or 2 and then places the data in the column.
UNPIVOT / PIVOT: Since you want to PIVOT data that exists in two columns, then you will want to UNPIVOT the mainphone1 and phone_cnt columns first to get them in the same column, then apply the PIVOT function.
The UNPIVOT code will be similar to the following:
select h_company_id, company_nm,
col+cast(seq as varchar(10)) col,
value
from
(
select h_company_id, company_nm,
cast(mainphone1 as varchar(15)) mainphone,
cast(phone_cnt as varchar(15)) phone_cnt,
row_number() over(partition by h_company_id order by mainphone1) seq
from yourtable
) d
unpivot
(
value
for col in (mainphone, phone_cnt)
) unpiv;
See Demo. This query gets the data in the following format:
| H_COMPANY_ID | COMPANY_NM | COL | VALUE |
---------------------------------------------------------------
| 11043 | 3I Group PLC | mainphone1 | 2079753731 |
| 11043 | 3I Group PLC | phone_cnt1 | 15 |
| 11043 | 3I Group PLC | mainphone2 | 2079757115 |
| 11043 | 3I Group PLC | phone_cnt2 | 1 |
| 20816 | 800 Flowers | mainphone1 | 5162377000 |
Then you apply the PIVOT function to the values in col:
select h_company_id, company_nm,
mainphone1, phone_cnt1, mainphone2, phone_cnt2
from
(
select h_company_id, company_nm,
col+cast(seq as varchar(10)) col,
value
from
(
select h_company_id, company_nm,
cast(mainphone1 as varchar(15)) mainphone,
cast(phone_cnt as varchar(15)) phone_cnt,
row_number() over(partition by h_company_id order by mainphone1) seq
from yourtable
) d
unpivot
(
value
for col in (mainphone, phone_cnt)
) unpiv
) src
pivot
(
max(value)
for col in (mainphone1, phone_cnt1, mainphone2, phone_cnt2)
) piv;
See SQL Fiddle with Demo.
Multiple Joins: You can also join on your table multiple times to get the result.
;with cte as
(
select h_company_id, company_nm, mainphone1, phone_cnt,
row_number() over(partition by h_company_id order by mainphone1) seq
from yourtable
)
select c1.h_company_id,
c1.company_nm,
c1.mainphone1,
c1.phone_cnt phone_cnt1,
c2.mainphone1 mainphone2,
c2.phone_cnt phone_cnt2
from cte c1
left join cte c2
on c1.h_company_id = c2.h_company_id
and c2.seq = 2
where c1.seq = 1;
See SQL Fiddle with Demo.
Dynamic SQL: Finally if you have an unknown number of values that you want to transform, then you will need to implement dynamic SQL to get the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(col+cast(seq as varchar(10)))
from
(
select row_number() over(partition by h_company_id order by mainphone1) seq
from yourtable
) d
cross apply
(
select 'mainphone', 1 union all
select 'phone_cnt', 2
) c (col, so)
group by seq, so, col
order by seq, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT h_company_id, company_nm,' + #cols + '
from
(
select h_company_id, company_nm,
col+cast(seq as varchar(10)) col,
value
from
(
select h_company_id, company_nm,
cast(mainphone1 as varchar(15)) mainphone,
cast(phone_cnt as varchar(15)) phone_cnt,
row_number() over(partition by h_company_id order by mainphone1) seq
from yourtable
) d
unpivot
(
value
for col in (mainphone, phone_cnt)
) unpiv
) x
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo. All give a result:
| H_COMPANY_ID | COMPANY_NM | MAINPHONE1 | PHONE_CNT1 | MAINPHONE2 | PHONE_CNT2 |
-----------------------------------------------------------------------------------------
| 20820 | 1st Source Corp. | 5742353000 | 3 | (null) | (null) |
| 20821 | 1st United Bancorp | 5613633400 | 2 | (null) | (null) |
| 20824 | 3D Systems Inc. | 8033273900 | 4 | 8033464010 | 1 |
| 11043 | 3I Group PLC | 2079753731 | 15 | 2079757115 | 1 |
| 20816 | 800 Flowers | 5162377000 | 3 | 5162377131 | 1 |
The following could work (assuming your table is called company):
SELECT
c1.h_company_id,
c1.company_nm,
c1.mainphone1,
c1.phone_cnt,
c2.mainphone1 AS mainphone2,
c2.phone_cnt AS phone_cnt2
FROM
company AS c1
LEFT JOIN
company AS c2 ON c2.h_company_id = c1.h_company_id
However, to respect good practice, wouldn't it be better to separate your data in two tables?
the company table, with 2 columns: h_company_id(PK) and company_nm
the phone table, with 4 columns: phone_id (PK), h_company_id (FK), mainphone and phone_cnt
It would allow you to have as many phone numbers per company as you want (including none).
Try this query. This will help you
SELECT t.H_COMPANY_ID,t.COMPANY_NM, a.mainphone1,a.PHONE_CNT,b.mainphone1 mainphone2,b.PHONE_CNT PHONE_CNT2 FROM table_name t
INNER JOIN
(
SELECT h_company_id,phone_cnt,mainphone1 FROM table_name
WHERE mainphone1
IN(
SELECT max(mainphone1) mainphone1 FROM table_name GROUP BY h_company_id
)
)a ON t.H_COMPANY_ID = a.h_company_id
INNER JOIN
(
SELECT h_company_id,phone_cnt,mainphone1 FROM table_name
WHERE mainphone1
IN(
SELECT min(mainphone1) mainphone1 from table_name GROUP BY h_company_id
)
)b ON t.H_COMPANY_ID = b.H_COMPANY_ID
GROUP BY t.H_COMPANY_ID,a.mainphone1,t.COMPANY_NM,a.PHONE_CNT,b.mainphone1,b.PHONE_CNT

How do I Pivot Vertical Data to Horizontal Data SQL with Variable Row Lengths?

Okay I have the following table.
Name ID Website
Aaron | 2305 | CoolSave1
Aaron | 8464 | DiscoWorld1
Adriana | 2956 | NewCin1
Adriana | 5991 | NewCin2
Adriana | 4563 NewCin3
I would like to transform it into the following way.
Adriana | 2956 | NewCin1 | 5991 | NewCin2 | 4563 | NewCin3
Aaron | 2305 | CoolSave1 | 8464 | DiscoWorld | NULL | NULL
As you can see i am trying to take the first name from the first table and make a single row with all the IDs / Websites associated with that name. The problem is, there is a variable amount of websites that may be associated with each name. To handle this i'd like to just make a table with with the number of fields sequal to the max line item, and then for the subsequent lineitems, plug in a NULL where there are not enough data.
In order to get the result, you will need to apply both the UNPIVOT and the PIVOT functions to the data. The UNPIVOT will take the columns (ID, website) and convert them to rows, once this is done, then you can PIVOT the data back into columns.
The UNPIVOT code will be similar to the following:
select name,
col+'_'+cast(col_num as varchar(10)) col,
value
from
(
select name,
cast(id as varchar(11)) id,
website,
row_number() over(partition by name order by id) col_num
from yt
) src
unpivot
(
value
for col in (id, website)
) unpiv;
See SQL Fiddle with Demo. This gives a result:
| NAME | COL | VALUE |
-------------------------------------
| Aaron | id_1 | 2305 |
| Aaron | website_1 | CoolSave1 |
| Aaron | id_2 | 8464 |
| Aaron | website_2 | DiscoWorld1 |
As you can see I applied a row_number() to the data prior to the unpivot, the row number is used to generate the new column names. The columns in the UNPIVOT must also be of the same datatype, I applied a cast to the id column in the subquery to convert the data to a varchar prior to the pivot.
The col values are then used in the PIVOT. Once the data has been unpivoted, you apply the PIVOT function:
select *
from
(
select name,
col+'_'+cast(col_num as varchar(10)) col,
value
from
(
select name,
cast(id as varchar(11)) id,
website,
row_number() over(partition by name order by id) col_num
from yt
) src
unpivot
(
value
for col in (id, website)
) unpiv
) d
pivot
(
max(value)
for col in (id_1, website_1, id_2, website_2, id_3, website_3)
) piv;
See SQL Fiddle with Demo.
The above version works great if you have a limited or known number of values. But if the number of rows is unknown, then you will need to use dynamic SQL to generate the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME( col+'_'+cast(col_num as varchar(10)))
from
(
select row_number() over(partition by name order by id) col_num
from yt
) t
cross apply
(
select 'id' col union all
select 'website'
) c
group by col, col_num
order by col_num, col
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT name,' + #cols + '
from
(
select name,
col+''_''+cast(col_num as varchar(10)) col,
value
from
(
select name,
cast(id as varchar(11)) id,
website,
row_number() over(partition by name order by id) col_num
from yt
) src
unpivot
(
value
for col in (id, website)
) unpiv
) x
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute(#query);
See SQL Fiddle with Demo. Both versions give the result:
| NAME | ID_1 | WEBSITE_1 | ID_2 | WEBSITE_2 | ID_3 | WEBSITE_3 |
------------------------------------------------------------------------
| Aaron | 2305 | CoolSave1 | 8464 | DiscoWorld1 | (null) | (null) |
| Adriana | 2956 | NewCin1 | 4563 | NewCin3 | 5991 | NewCin2 |