数据透视表SQL

Bru*_*nto 1 sql sql-server pivot sql-server-2008

我有3张桌子.

1 - 学生

| student_code |  name   |  
--------------------------
| 1            |  katia  |   
| 2            |  roger  |   
| 3            |  ken    | 
Run Code Online (Sandbox Code Playgroud)

2 - 问题

| question_code|  question       |  
----------------------------------
| 1            |  father' name   |   
| 2            |  favorite fruit |   
| 3            |  first teacher  | 
Run Code Online (Sandbox Code Playgroud)

3 - 答案

| student_code | question_code | answer  |  
-------------------------------------------
| 1            | 1             |  katia  |    
| 1            | 2             |  banana |   
| 2            | 1             |   ken   | 
Run Code Online (Sandbox Code Playgroud)

当我加入这个3时,我有800.000行,如下所示:

| name  | question        | answer  |  
-------------------------------------
| katia| favorite fruit   |  banana |   
| katia| father's name    |  paul   |   
| roger| father's name    |  aaron  | 
Run Code Online (Sandbox Code Playgroud)

我需要转换列的问题行,每行只维持1个学生.

我搜索了数据透视表,但我无法使它工作.

OBS:并非每个学生都有问题

编辑:我认为这个问题不重复,因为PIVOT功能非常具体,另一个问题不回答我的问题.

Tar*_*ryn 7

由于您使用的是SQL Server 2008,因此可以使用该PIVOT函数来获取结果.此函数将通过使用聚合函数将您的数据行转换为列.由于您的数据是字符串,因此您将仅限于使用maxmin聚合函数.

如果您的列数有限,则可以对查询进行硬编码.基本语法是:

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;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo.

但是如果您的问题数量未知,那么您将需要使用动态SQL来生成结果.这将创建您希望在最终结果中具有的问题列表,并且您将创建将要执行的sql字符串.代码类似于:

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;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo.两者都会给出结果:

|  NAME | FATHER' NAME | FAVORITE FRUIT | FIRST TEACHER |
|-------|--------------|----------------|---------------|
| katia |        katia |         banana |        (null) |
|   ken |       (null) |         (null) |        (null) |
| roger |          ken |         (null) |        (null) |
Run Code Online (Sandbox Code Playgroud)

  • @ScottStroz:有些概念很容易,甚至被认为是SQL的基础,其他概念更复杂,最新.我相信PIVOT代表后者.当一个人*完全*不熟悉复杂的东西时,我认为为他们完成这项工作是完全没错的*并且*解释正在做什么,为什么以及如何运作.由于有许多PIVOT问题和答案,一个*可能*认为只提到正确的关键字,就像在删除的答案中一样,但是在我看来应该是一个评论,因为它是一个*通用*指针,正是因为PIVOT并不那么容易. (4认同)
  • @JoeRinehart我可以保证这不是复制和粘贴的答案,我专门为这个用户写了这个.PIVOT是一个让人们很难理解的概念,因此我通常会为用户编写一个特定的答案. (3认同)
  • @ScottStroz嗯,我想这比没有给鱼好,也不教如何捕鱼,只是给这个人一个"钓鱼指南"并说"读它" (3认同)
  • @ScottStroz您可以将评论标记为具有攻击性,并解释为什么如果您想要一个mod来查看它,您会发现它有价值.他们不只是在没有理由的情况下删除评论 (2认同)