Make 1 row out of many rows from another table - sql

I have a MSSQL database which in one table holds bio info about a person:
ID: Name : Age : Sex
In another table it holds their answers to a number of questions like this:
PersonID : QuestionID : Answer
Is it possible to display all of them via MSSQLMSE into one record like this:
ID : Name : Age : Sex : Question1Answer : Question2Answer : Question3Answer : And so on?

Try this:
SELECT ID, name, age, sex, Question1answer, Question2answer
FROM
(
SELECT
p.Id,
p.Name,
p.Age,
p.sex,
questionanswer = 'Question' + CAST(q.questionid AS VARCHAR(10)) + 'answer',
q.Answer
FROM Persons p
INNER JOIN Questions q ON p.Id = q.UserID
) t
PIVOT
(
MAX(Answer)
FOR questionanswer IN([Question1answer], [Question2answer])
) p;
SQL Fiddle Demo
This will give you:
| ID | NAME | AGE | SEX | QUESTION1ANSWER | QUESTION2ANSWER |
-----------------------------------------------------------------
| 1 | Ahmed | 25 | M | Yes | No |
| 2 | Mohammed | 30 | M | No | Never |
| 3 | Sara | 25 | F | No | Never |
However: If you want to do this dynamically for any number of questions per user, you can do this:
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct
',' +
QUOTENAME('Question' +
CAST(questionid AS VARCHAR(10)) +
'answer')
FROM questions
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
SET #query = 'SELECT ID, name, age, sex, ' + #cols +
' FROM
(
SELECT
p.Id,
p.Name,
p.Age,
p.sex,
questionanswer = ''Question'' +
CAST(q.questionid AS VARCHAR(10)) +
''answer'',
q.Answer
FROM Persons p
INNER JOIN Questions q ON p.Id = q.UserID
) t
PIVOT
(
MAX(Answer)
FOR questionanswer IN( ' + #cols + ') ) p ';
SQL Fiddle Dynamic Demo

select ID,Name,Age,Sex,
(select top 1 Answer from Questions
where PersonId=prerson.id AND QuestionID=1) as Question1Answer,
(select top 1 Answer from Questions
where PersonId=prerson.id AND QuestionID=2) as Question2Answer,
(select top 1 Answer from Questions
where PersonId=prerson.id AND QuestionID=3) as Question3Answer
from prerson

The PIVOT command in sql server would be appropriate to transpose table results, see http://msdn.microsoft.com/en-us/library/ms177410(v=sql.100).aspx
The script below works with a predefined set of questions. For a variable amount of columns this link would help http://blog-mstechnology.blogspot.com/2010/06/t-sql-pivot-operator-with-dynamic.html.
DECLARE #Person TABLE(
ID INT,
Name VARCHAR(50),
Age INT,
Sex CHAR(1)
)
DECLARE #Questions TABLE(
ID INT,
QuestionID INT,
Question VARCHAR(200),
Answer VARCHAR(200)
)
INSERT INTO #Person VALUES
(1,'Andrew',56,'M'),
(2,'Marge',65,'F')
INSERT INTO #Questions VALUES
(1,1,'Question1','Andrews Answer 1'),
(1,2,'Question2','Andrews Answer 2'),
(2,1,'Question1','Marge Answer 1'),
(2,3,'Question3','Marge Answer 3')
SELECT ID,Age,Name,Sex,
[1] AS 'Question1Answer',
[2] AS 'Question2Answer',
[3] AS 'Question3Answer'
FROM(
SELECT P.ID,P.Age,P.Name,P.Sex,Q.QuestionID,Q.Answer
FROM #Person P
INNER JOIN #Questions Q ON Q.ID = P.ID
) Source
PIVOT
(
MAX(Answer)
FOR QuestionID IN ([1],[2],[3])
)AS PT

Try this:
SELECT
ID,
Name,
Age,
Sex,
[1] AS Question1Answer,
[2] AS Question1Answer,
[3] AS Question1Answer
FROM
(SELECT
i.ID,
i.Name,
i.Age,
i.Sex,
q.QuestionId,
q.Answer
FROM
dbo.Info AS i
INNER JOIN dbo.Questions AS q on q.ID = i.ID) AS m
PIVOT
(
MAX(Answer) FOR QuestionId in ([1],[2],[3])
) as PivotTable

I think this (SQL Fiddle here) is what you are looking for. For a given person id;
Note: p = Person Table, a = Answer Table and qId = QuestionId
DECLARE #S VARCHAR(Max)
DECLARE #PersonId INT = 1
SELECT #S=ISNULL(#S+' : ','') + convert(varchar(10), id) +' : '+ name
+' : '+ convert(varchar(10), age)+' : '+sex
FROM p
WHERE p.Id = #PersonId
SELECT #S=ISNULL(#S+' : ','') +
'Question' + convert(varchar(10), qid) +'Answer : '+ answer
FROM a
WHERE pId = #PersonId
SELECT #S
--Following results is in one line
--1 : X : 25 : M : Question11Answer : Here is my answer for 11 :
--Question12Answer : Here is my answer for 12 :
--Question101Answer : Here is my answer for 101

Try this method: (Set compatability level of database to 90 or higher)
begin
Declare #MainSQL nVarchar(Max)
Declare #Param nVarchar(Max)
Declare #QId int
set #Param = ''
Declare curParam Cursor For select Distinct QuestionID from Questions
open curParam
Fetch next from curParam into #QId
While ##Fetch_Status = 0
Begin
set #Param = #Param +'[' +convert(nVarchar,#QId ) + '],'
Fetch next from curParam into #QId
End
close curParam;
Deallocate curParam;
set #Param = left(#Param,len(#Param)-1)
Set #MainSQL = 'Select ID,Name,Age,***
From
(select P.ID,Name,Age,
Q.QuestionID, Q.Answer From Person P Left outer join
Questions Q
ON P.ID = Q.PersonID) S
Pivot
(Max(Answer)
For QuestionID in(***)
) as Pvt'
Set #MainSQL =replace(#MainSQL,'***',#Param);
--print #MainSQL
execute sp_executesql #MainSQL
End

Related

sql server sort dynamic pivot on large set of data

I am having trouble sorting a pivot based on a quite large set of data. I have looked at many examples, but none of them seems to address the issue of volume - or perhaps I am just missing something. I have had a very good look here: Sort Columns For Dynamic Pivot and PIVOT in sql 2005 and found much good advise, but I still cannot find the correct way to sort my pivot.
I am using the following sql. It pivots the columns, but the result needs to be sorted for readability:
SELECT a.* INTO #tempA
FROM (SELECT top (5000) id, email, CONVERT(varchar,ROW_NUMBER() OVER
(PARTITION BY email ORDER BY id)) AS PIVOT_CODE FROM Email) a
order by PIVOT_CODE
DECLARE #cols AS NVARCHAR(MAX),
#sql AS NVARCHAR(MAX)
SELECT #cols =STUFF((SELECT DISTINCT ', ' + QUOTENAME(col)
FROM #tempA WITH (NOLOCK)
cross apply
(
SELECT 'id_' + PIVOT_CODE, id
) c (col, so)
group by col, so
--order by col
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #sql = 'SELECT email, '
+#cols+
'INTO ##AnotherPivotTest FROM
(
SELECT email,
col,
value
FROM #tempA WITH (NOLOCK)
cross apply
(
values
(''id_'' + PIVOT_CODE, id)
) c (col, value)
) d
pivot
(
max(value)
for col in ('
+ #cols+
')
) piv'
EXEC (#sql)
SELECT * FROM ##AnotherPivotTest
The result is a chaos to look at:
==============================================================================================
| email | id_19 | id_24 | id_2 | id_16 | id_5 | id_9 | id_23 | .... | id_1 | .... | id_10 |
==============================================================================================
| xx#yy.dk | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | 1234 | NULL | NULL |
==============================================================================================
I would very much like the Ids to be sorted - beginning with id_1.
As you can see, I have attempted to place an 'order by' in the selection for 'cols', but that gives me the error: "ORDER BY items must appear in the select list if SELECT DISTINCT is specified." And without DISTINCT, I get another error: "The number of elements in the select list exceeds the maximum allowed number of 4096 elements."
I'm stuck, so any help will be greatly appreciated!
Not sure what causes the problem but I've solved my order problem in my pivot table by inserting the data coming from tempA into another temp table and ordering them there
INSERT INTO #tempB
SELECT * FROM #tempA
ORDER BY PIVOT_CODE
Then selecting distinct ones like so:
SELECT #cols = #cols + QUOTENAME(PIVOT_CODE) + ',' FROM (SELECT DISTINCT PIVOT_CODE FROM #tempB ORDER BY PIVOT_CODE)
SELECT #cols = SUBSTRING(#cols, 0, LEN(#cols)) --trims "," at end
You can also just use a cursor to determine your cols and the order them
Cursor with cols ordered
declare #gruppe nvarchar(max)
declare #gruppeSql nvarchar(max)
declare #SQL nvarchar(max)
DECLARE myCustomers CURSOR FOR
select top 10 FirstName from [dbo].[DimCustomer] Order by FirstName
set #gruppeSql = ''
OPEN myCustomers
FETCH NEXT FROM myCustomers INTO #gruppe
IF (##FETCH_STATUS>=0)
BEGIN
SET #gruppeSql = #gruppeSql +'[' +#gruppe+']'
FETCH NEXT FROM myCustomers INTO #gruppe
END
WHILE (##FETCH_STATUS<>-1)
BEGIN
IF (##FETCH_STATUS<>-2)
SET #gruppeSql = #gruppeSql + ',[' +#gruppe+']'
FETCH NEXT FROM myCustomers INTO #gruppe
END
CLOSE myCustomers
DEALLOCATE myCustomers
SET #gruppeSql = replace(#gruppesql,'''','')
/*Select to preview your cols*/
select #gruppeSql
Dynamic pivot
SET #SQL = '
 Select *
from
(
SELECT SalesAmount, FirstName
FROM [AdventureWorksDW2014].[dbo].[FactInternetSales] a inner join dbo.DimCustomer b on a.CustomerKey = b.CustomerKey
) x
pivot
(
sum(SalesAmount)
for FirstName in ('+#gruppesql+')
) p'
print #sql
exec(#sql)

Convert row to column when data are not numbers

I have a Question table, which has a unknown number of questions.(first table in the figure)
I also have an AnswerSheet table, which records student's answer to question.(second table in the figure)
Create table Question
(
Id int,
Text nvarchar(50),
PRIMARY KEY (Id)
)
Create table AnswerSheet
(
StudentId int,
QuestionId int,
Answer nvarchar(50),
PRIMARY KEY (StudentId,QuestionId),
FOREIGN KEY (QuestionId) REFERENCES Question (Id)
)
insert into Question
values(1,'What''s your age'),
(2,'What''s your gender'),
(3,'When do you go home'),
....
insert into AnswerSheet
values(500,1,'20'),
(500,2,'Male'),
(500,3,'5:00pm'),
(501,1,'50'),
(502,2,'I don''t know##'),
....
How do I write a SQL to generate a table like this?
StudentId What's your age What's your gender When do you go home ...
--------- ---------------- ------------------- -------------------
500 20 Male 5:00pm ...
501 50 NULL NULL
502 NULL I don''t know## NULL ...
I feel Pivot is promising but I'm not sure how to use it especially PIVOT requires an aggreation function but my data are not numbers.
Assuming you wanted to go Dynamic
Example
Declare #SQL varchar(max) = Stuff((Select ',' + QuoteName(Text) From Question Order by ID For XML Path('')),1,1,'')
Select #SQL = '
Select *
From (
Select StudentID
,Col = B.Text
,Value = A.Answer
From AnswerSheet A
Join Question B on A.QuestionID=B.ID
) A
Pivot (max(Value) For [Col] in (' + #SQL + ') ) p'
Exec(#SQL);
Returns
StudentID What's your age What's your gender When do you go home
500 20 Male 5:00pm
501 50 NULL NULL
502 NULL I don't know## NULL
If it Helps, the Generated SQL Looks Like This
Select *
From (
Select StudentID
,Col = B.Text
,Value = A.Answer
From AnswerSheet A
Join Question B on A.QuestionID=B.ID
) A
Pivot (max(Value) For [Col] in ([What's your age],[What's your gender],[When do you go home]) ) p
I know this question is answered by accepted one, but I hope this approach helps others.
simply you can achieve your goal without using Pivot, via using Group by as next:-
Select b.StudentId,
Min(Case a.text When 'What''s your age' Then b.answer End) 'What''s your age',
Min(Case a.text When 'What''s your gender' Then b.answer End) 'What''s your gender',
Min(Case a.text When 'When do you go home' Then b.answer End) 'When do you go home'
from Question a inner join AnswerSheet b
on a.id = b.Questionid
Group By StudentId
and you mentioned unknown number of questions, so the next code for dynamic:-
DECLARE #DynamicQuestions VARCHAR(8000)
SELECT #DynamicQuestions = Stuff(
(SELECT N' Min(Case a.text When''' + replace (Text,'''','''''')
+ ''' Then b.answer End) '''
+ replace (Text,'''','''''') + ''','
FROM Question FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),1,1,N'')
select #DynamicQuestions =
left(#DynamicQuestions,len(#DynamicQuestions)-1) -- for Removing last comma
exec ('Select b.StudentId, '+ #DynamicQuestions +
'from Question a inner join AnswerSheet b
on a.id = b.Questionid
Group By StudentId' )
Result:-
StudentId What's your age What's your gender When do you go home
500 20 Male 5:00pm
501 50 NULL NULL
502 NULL I don't know## NULL

Stored procedure that returns a table from 2 combined

I am trying to write a stored procedure which returns a result combining 2 table variables which looks something like this.
Name | LastName | course | course | course | course <- Columns
Name | LastName | DVA123 | DVA222 | nothing | nothing <- Row1
Pete Steven 200 <- Row2
Steve Lastname 50 <- Row3
From these 3 tables
Table Staff:
Name | LastName | SSN |
Steve Lastname 234
Pete Steven 132
Table Course Instance:
Course | Year | Period |
DVA123 2013 1
DVA222 2014 2
Table Attended by:
Course | SSN | Year | Period | Hours |
DVA123 234 2013 1 200
DVA222 132 2014 2 50
I am taking #year as a parameter that will decide what year in the course will be displayed in the result.
ALTER proc [dbo].[test4]
#year int
as
begin
-- I then declare the 2 tables which I will then store the values from the tables
DECLARE #Table1 TABLE(
Firstname varchar(30) NOT NULL,
Lastname varchar(30) NOT NULL
);
DECLARE #Table2 TABLE(
Course varchar(30) NULL
);
Declare #variable varchar(max) -- variable for saving the cursor value and then set the course1 to 4
I want at highest 4 results/course instances which I later order by the period of the year
declare myCursor1 CURSOR
for SELECT top 4 period from Course instance
where year = #year
open myCursor1
fetch next from myCursor1 into #variable
--print #variable
while ##fetch_status = 0
Begin
UPDATE #Table2
SET InstanceCourse1 = #variable
where current of myCursor1
fetch next from myCursor1 into #variable
print #variable
End
Close myCursor1
deallocate myCursor1
insert into #table1
select 'Firstname', 'Lastname'
insert into #table1
select Firstname, Lastname from staff order by Lastname
END
select * from #Table1 -- for testing purposes
select * from #Table2 -- for testing purposes
--Then i want to combine these tables into the output at the top
This is how far I've gotten, I don't know how to get the courses into the columns and then get the amount of hours for each staff member.
If anyone can help guide me in the right direction I would be very grateful. My idea about the cursor was to get the top (0-4) values from the top4 course periods during that year and then add them to the #table2.
Ok. This is not pretty. It is a really ugly dynamic sql, but in my testing it seems to be working. I have created an extra subquery to get the courses values as the first row and then Union with the rest of the result. The top four courses are gathered by using ROW_Number() and order by Year and period. I had to make different versions of the courses string I am creating in order to use them for both column names, and in my pivot. Give it a try. Hopefully it will work on your data as well.
DECLARE #Year INT
SET #Year = 2014
DECLARE #Query NVARCHAR(2000)
DECLARE #CoursesColumns NVARCHAR(2000)
SET #CoursesColumns = (SELECT '''' + Course + ''' as c' + CAST(ROW_NUMBER() OVER(ORDER BY Year, Period) AS nvarchar(50)) + ',' AS 'data()'
FROM AttendedBy where [Year] = #Year
for xml path(''))
SET #CoursesColumns = LEFT(#CoursesColumns, LEN(#CoursesColumns) -1)
SET #CoursesColumns =
CASE
WHEN CHARINDEX('c1', #CoursesColumns) = 0 THEN #CoursesColumns + 'NULL as c1, NULL as c2, NULL as c3, NULL as c4'
WHEN CHARINDEX('c2', #CoursesColumns) = 0 THEN #CoursesColumns + ',NULL as c2, NULL as c3, NULL as c4'
WHEN CHARINDEX('c3', #CoursesColumns) = 0 THEN #CoursesColumns + ', NULL as c3, NULL as c4'
WHEN CHARINDEX('c4', #CoursesColumns) = 0 THEN #CoursesColumns + ', NULL as c4'
ELSE #CoursesColumns
END
DECLARE #Courses NVARCHAR(2000)
SET #Courses = (SELECT Course + ' as c' + CAST(ROW_NUMBER() OVER(ORDER BY Year, Period) AS nvarchar(50)) + ',' AS 'data()'
FROM AttendedBy where [Year] = #Year
for xml path(''))
SET #Courses = LEFT(#Courses, LEN(#Courses) -1)
SET #Courses =
CASE
WHEN CHARINDEX('c1', #Courses) = 0 THEN #Courses + 'NULL as c1, NULL as c2, NULL as c3, NULL as c4'
WHEN CHARINDEX('c2', #Courses) = 0 THEN #Courses + ',NULL as c2, NULL as c3, NULL as c4'
WHEN CHARINDEX('c3', #Courses) = 0 THEN #Courses + ', NULL as c3, NULL as c4'
WHEN CHARINDEX('c4', #Courses) = 0 THEN #Courses + ', NULL as c4'
ELSE #Courses
END
DECLARE #CoursePivot NVARCHAR(2000)
SET #CoursePivot = (SELECT Course + ',' AS 'data()'
FROM AttendedBy where [Year] = #Year
for xml path(''))
SET #CoursePivot = LEFT(#CoursePivot, LEN(#CoursePivot) -1)
SET #Query = 'SELECT Name, LastName, c1, c2, c3, c4
FROM (
SELECT ''Name'' as name, ''LastName'' as lastname, ' + #CoursesColumns +
' UNION
SELECT Name, LastName,' + #Courses +
' FROM(
SELECT
s.Name
,s.LastName
,ci.Course
,ci.Year
,ci.Period
,CAST(ab.Hours AS NVARCHAR(100)) AS Hours
FROM Staff s
LEFT JOIN AttendedBy ab
ON
s.SSN = ab.SSN
LEFT JOIN CourseInstance ci
ON
ab.Course = ci.Course
WHERE ci.Year=' + CAST(#Year AS nvarchar(4)) +
' ) q
PIVOT(
MAX(Hours)
FOR
Course
IN (' + #CoursePivot + ')
)q2
)q3'
SELECT #Query
execute(#Query)
Edit: Added some where clauses so only courses from given year is shown. Added Screenshot of my results.
try this
DECLARE #CourseNameString varchar(max),
#query AS NVARCHAR(MAX);
SET #CourseNameString=''
select #CourseNameString = STUFF((SELECT distinct ',' + QUOTENAME(Course)
FROM Attended where [Year]= 2013
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = '
select Name,LastName,'+#CourseNameString+' from Staff as e inner join (
SELECT * FROM
(SELECT [Hours],a.SSN,a.Course as c FROM Attended as a inner JOIN Staff as s
ON s.SSN = s.SSN) p
PIVOT(max([Hours])FOR c IN ('+#CourseNameString+')) pvt)p
ON e.SSN = p.SSN'
execute(#query)
Use subquery like this one :
SELECT Firstname, Lastname, (select instanceCourse1 from table2) as InstanceCourse1 from Table1

T:SQL: select values from rows as columns

I have a table for Profiles stores profile properties values in row style, ex:
[ProfileID] [PropertyDefinitionID] [PropertyValue]
1 6 Jone
1 7 Smith
1 8 Mr
1 3 50000
and another table for property definitions :
[PropertyDefinitionID] [PropertyName]
6 FirstName
7 LastName
8 Prefix
3 Salary
How to use PIVOT or any other way to show it in this way:
[ProfileID] [FirstName] [LastName] [Salary]
1 Jone Smith 5000
It's easy to do this without PIVOT keyword, just by grouping
select
P.ProfileID,
min(case when PD.PropertyName = 'FirstName' then P.PropertyValue else null end) as FirstName,
min(case when PD.PropertyName = 'LastName' then P.PropertyValue else null end) as LastName,
min(case when PD.PropertyName = 'Salary' then P.PropertyValue else null end) as Salary
from Profiles as P
left outer join PropertyDefinitions as PD on PD.PropertyDefinitionID = P.PropertyDefinitionID
group by P.ProfileID
you can also do this with PIVOT keyword
select
*
from
(
select P.ProfileID, P.PropertyValue, PD.PropertyName
from Profiles as P
left outer join PropertyDefinitions as PD on PD.PropertyDefinitionID = P.PropertyDefinitionID
) as P
pivot
(
min(P.PropertyValue)
for P.PropertyName in ([FirstName], [LastName], [Salary])
) as PIV
UPDATE: For dynamic number of properties - take a look at Increment value in SQL SELECT statement
It looks like you might have an unknown number of PropertyName's that you need to turn into columns. If that is the case, then you can use dynamic sql to generate the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(PropertyName)
from propertydefinitions
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT profileid, ' + #cols + ' from
(
select p.profileid,
p.propertyvalue,
d.propertyname
from profiles p
left join propertydefinitions d
on p.PropertyDefinitionID = d.PropertyDefinitionID
) x
pivot
(
max(propertyvalue)
for propertyname in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo.

Increment value in SQL SELECT statement

Here is the sample code for what I am trying to do and below is the result:
CREATE TABLE dbo.#TempDoc_DocContRoles (DocID int null, FullName varchar(500), DocContRole
varchar (100), NumRole int null)
INSERT INTO #TempDoc_DocContRoles(DocID, FullName, DocContRole)
SELECT
d.DocID, c.FirstName + ' ' + c.LastName as FullName, ldcro.DocContRole
FROM
Document as d
JOIN
dbo.Split( ',','30,31') AS l ON d.DocID = cast(l.[Value] AS int)
JOIN
Doc_Contact AS dc ON d.DocID = dc.DocID
JOIN
Contact AS c ON dc.P_Number = c.P_Number
LEFT JOIN
lkpDocContactRole AS ldcro ON ldcro.DocContRoleID = dc.DocContRoleID
JOIN
dbo.Split( ',','1,2,7') AS r ON ldcro.DocContRoleID = cast(r.[Value] AS int)
CREATE TABLE dbo.#MaxNumRoles (DocID int null, DocContRole varchar(100), NumRole int null)
INSERT INTO dbo.#MaxNumRoles (DocID,DocContRole,NumRole)
SELECT
DocID, DocContRole, COUNT(*)
FROM
dbo.#TempDoc_DocContRoles
GROUP BY
DocID, DocContRole
HAVING
Count(*) > 0
UPDATE td
SET td.NumRole = mr.NumRole
FROM dbo.#TempDoc_DocContRoles as td
INNER JOIN dbo.#MaxNumRoles as mr ON td.DocContRole = mr.docContRole
SELECT * FROM dbo.#TempDoc_DocContRoles
DROP TABLE dbo.#TempDoc_DocContRoles
DROP TABLE dbo.#MaxNumRoles
Result:
DocID FullName DocContRole NumRole
30 Smith Author 3
30 Daln Staff 2
30 Dolby Author 3
31 Tammy Author 3
30 Barny Author 3
30 Sanny Res Coor 1
30 Johny Staff Rev 2
I would like to actually get:
DocID FullName DocContRole NumRole
30 Smith Author 1
30 Daln Staff 1
30 Dolby Author 2
31 Tammy Author 1
30 Barny Author 3
30 Sanny Res Coor 1
30 Johny Staff Rev 2
It should increment the number in NumRole per docContRole and docID (ex Author 1, Author 2 etc). Currently it gives the total number of authors per DocID.
My ultimate goal is to get something like
DocID Author_1 Author_2 Author_3 Staff_1 Staff_2 ResCoor_1
30 Smith Dolby Barny Daln Johny Sanny
31 Tammy
You can try this
select
td.DocID, td.FullName, td.DocContRole,
row_number() over (partition by td.DocID, td.DocContRole order by td.FullName) as NumRole
from dbo.#TempDoc_DocContRoles as td
So dynamic SQL will be smth like that
SQL FIDDLE EXAMPLE
create table #t2
(
DocID int, FullName nvarchar(max),
NumRole nvarchar(max)
)
declare #pivot_columns nvarchar(max), #stmt nvarchar(max)
insert into #t2
select
td.DocID, td.FullName,
td.DocContRole +
cast(
row_number() over
(partition by td.DocID, td.DocContRole order by td.FullName)
as nvarchar(max)) as NumRole
from t as td
select
#pivot_columns =
isnull(#pivot_columns + ', ', '') +
'[' + NumRole + ']'
from (select distinct NumRole from #t2) as T
select #stmt = '
select *
from #t2 as t
pivot
(
min(FullName)
for NumRole in (' + #pivot_columns + ')
) as PT'
exec sp_executesql
#stmt = #stmt