1

I have 3 tables.

1 - Student

| student_code |  name   |  
--------------------------
| 1            |  katia  |   
| 2            |  roger  |   
| 3            |  ken    | 

2 - Question

| question_code|  question       |  
----------------------------------
| 1            |  father' name   |   
| 2            |  favorite fruit |   
| 3            |  first teacher  | 

3 - Answers

| student_code | question_code | answer  |  
-------------------------------------------
| 1            | 1             |  katia  |    
| 1            | 2             |  banana |   
| 2            | 1             |   ken   | 

When I join this 3, I've 800.000 rows like this:

| name  | question        | answer  |  
-------------------------------------
| katia| favorite fruit   |  banana |   
| katia| father's name    |  paul   |   
| roger| father's name    |  aaron  | 

I need convert the questions rows for columns and maintain only 1 student per row.

I've searched for pivot table but I can't make it works.

OBS: Not every student has all questions

EDIT: I think this question is not duplicated because PIVOT function is very specific , the other question doesn't answer the mine.

Bruno Pinto
  • 2,013
  • 3
  • 23
  • 33

1 Answers1

7

Since you are using SQL Server 2008, you can use the PIVOT function to get the result. This function will convert your rows of data into columns through the use of an aggregate function. Since your data is a string, then you will be limited to using either the max or min aggregate functions.

If you have a limited number of columns, then you can hard-code your query. The basic syntax will be:

select name,
  [father' name], 
  [favorite fruit],
  [first teacher]
from
(
  select q.question,
    a.answer,
    s.name
  from student s
  left join answers a
    on s.student_code = a.student_code
  left join question q
    on a.question_code = q.question_code 
) d
pivot
(
  max(answer)
  for question in ([father' name], [favorite fruit],
                   [first teacher])
) piv;

See SQL Fiddle with Demo.

But if you have an unknown number of questions, then you will need to use dynamic SQL to generate the result. This will create a list of the questions that you want to have in the final result and you will create a sql string that will be executed. The code will be similar to:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(question) 
                    from question
                    group by question_code, question
                    order by question_code
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = N'SELECT name, ' + @cols + N' 
            from 
            (
              select q.question,
                a.answer,
                s.name
              from student s
              left join answers a
                on s.student_code = a.student_code
              left join question q
                on a.question_code = q.question_code 
            ) x
            pivot 
            (
                max(answer)
                for question in (' + @cols + N')
            ) p '

execute sp_executesql @query;

See SQL Fiddle with Demo. Both will give a result:

|  NAME | FATHER' NAME | FAVORITE FRUIT | FIRST TEACHER |
|-------|--------------|----------------|---------------|
| katia |        katia |         banana |        (null) |
|   ken |       (null) |         (null) |        (null) |
| roger |          ken |         (null) |        (null) |
Taryn
  • 242,637
  • 56
  • 362
  • 405
  • 3
    @JoeRinehart I can guarantee that this was not a copy and paste answer, I wrote this specifically for this user. PIVOT is a concept that is very difficult for people to understand, so I typically will write an answer specific for the user. – Taryn Jan 13 '14 at 15:15
  • 2
    @ScottStroz You can flag the comment as offensive and explain why you find it flag worthy if you want a mod to look at it. They are not just gonna delete the comment without a reason – Lamak Jan 13 '14 at 15:53
  • 1
    @ScottStroz eegads man move on already. I've seen plenty of your answers they have code samples and are genuinely good answers. So why do you have such a ravenous desire to defend that crappy answer? – Zane Jan 13 '14 at 15:56
  • @ScottStroz Then there's not much more to do than wait for the mods to act on that flag. You will be able to see in your profile wether your flag was find useful or not – Lamak Jan 13 '14 at 15:57
  • Because I do not feel it is a crappy answer. – Scott Stroz Jan 13 '14 at 15:58
  • @bluefeet, I've tried your code here, but it's duplicating the rows. Each student have 1 row for each answer. – Bruno Pinto Jan 13 '14 at 15:58
  • @Manjuba can you expand your dataset? Or even edit this sql fiddle with more data - http://sqlfiddle.com/#!3/1dee6/6 – Taryn Jan 13 '14 at 15:59
  • 4
    @ScottStroz: Some concepts are easy or even considered basic to SQL, others are more complex and recent. I believe PIVOT represents the latter. When a person is *completely* unfamiliar with something complex, I think it is perfectly fine to do the job for them *and* explain what is being done, why, and how it works. As there are many PIVOT questions and answers, one *might* think that just mentioning the right keyword, like in the deleted answer, is enough, but in my opinion that should be a comment, since it's a *general* pointer, precisely because PIVOTs aren't that easy. – Andriy M Jan 13 '14 at 16:11
  • @bluefeet, i got Schema Creation Failed: MODIFY FILE encountered operating system error 112(There is not enough space on the disk.) while attempting to expand the physical file 'c:\Program Files\Microsoft SQL Server\MSSQL10_50.SQLEXPRESS2008\MSSQL\DATA\db_3_4caf9.mdf'.: – Bruno Pinto Jan 13 '14 at 16:17
  • @bluefeet I figured this, I'm putting just some data, not all my base. I'm trying put minus data to see how it works. – Bruno Pinto Jan 13 '14 at 16:23
  • @bluefeet Just 3 lines and each row and nothing... – Bruno Pinto Jan 13 '14 at 16:24
  • @bluefeet My data is just like my question... I don't know why your code is duplicating the lines... – Bruno Pinto Jan 13 '14 at 16:32
  • @AndriyM Got it. 'Teach a man to fish, unless it is a difficult fish to catch, then just give it to him and hope that he understands how you caught it.' That seems counter-intuitive to what I have understood SO is supposed to be. – Scott Stroz Jan 13 '14 at 16:48
  • 3
    @ScottStroz Well, I guess that's better than not giving the fish and also don't teach how to fish, just give the man a "guide to fishing" and saying "read it" – Lamak Jan 13 '14 at 16:55
  • 1
    @ScottStroz: Not sure what you are driving at. If you were to show someone how to fish, wouldn't you first, well, *show* them? I mean, would it be awfully unnatural to start with doing everything yourself for the first time, explaining along the way what you are doing? (Not really expecting your answer to that, just explaining what I meant with my former comment.) – Andriy M Jan 13 '14 at 16:55