当前位置: 首页 > 面试题库 >

SQL Server:具有自定义列名称的数据透视

宓诚
2023-03-14
问题内容

我需要使用自定义列名来旋转表。请参阅下面的表格格式。

当前格式

ID            question                            Answer
4482515   I would like to be informed  by mail.   No
4482515   Plan to Purchase?                       Over 12 months
4482515   Test Question Text                      some Answer

我想以以下格式显示数据。

所需格式

ID       question 1                            Answer1   question 2         Answer 2
4482515  I would like to be informed  by mail. NO        Plan to Purchase?  Over 12 months

请注意:我不知道连续出现的问题和答案的数量,因此应动态生成列的question1 Answer1。

谢谢

编辑:谢谢您的帮助,我尝试一下您提供给我的动态代码,并得到此错误。

Msg 8167, Level 16, State 1, Line 1
The type of column "answer" conflicts with the type of other columns specified in the UNPIVOT list.

我的桌子是

RID         Question    Answer
4482515 Some Question1  Some Answer1
4482515 Some Question2  Some Answer2
4482515 Some Question3  Some Answer3
4484094 Some Question1  Answer1
4484094 Some Question2  Answer2
4484094 Some Question3  Answer3
4484094 Some Question4  Answer4

我打印出SQL,结果如下。

SELECT rid, [question1],[answer1],[question2],[answer2],[question3],[answer3],[question4],[answer4],[question5],[answer5],[question6],[answer6]
              from
              (
                select rid,
                  col+cast(rn as varchar(10)) col,
                  value
                from
                (
                  select rid, question, answer,
                    row_number() over(partition by rid order by rid, question) rn
                  from #tmp_question
                ) src
                unpivot
                (
                  value
                  for col in (question, answer)
                ) unpiv
              ) d
              pivot 
              (
                  max(value)
                  for col in ([question1],[answer1],[question2],[answer2],[question3],[answer3],[question4],[answer4],[question5],[answer5],[question6],[answer6])
              ) p

我的原始SQL代码也在下面

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

select @cols = STUFF((SELECT ',' + QUOTENAME(c.col+cast(rn as varchar(10))) 
                    from 
                    (
                      select row_number() over(partition by rid 
                                               order by rid, question) rn
                      from #tmp_question
                    ) d
                    cross apply
                    (
                      select 'question' col, 1 sort union all select 'answer', 2
                    ) c
                    group by col, rn, sort
                    order by rn, sort
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT rid, ' + @cols + '
              from
              (
                select rid,
                  col+cast(rn as varchar(10)) col,
                  value
                from
                (
                  select rid, question, answer,
                    row_number() over(partition by rid order by rid, question) rn
                  from #tmp_question
                ) src
                unpivot
                (
                  value
                  for col in (question, answer)
                ) unpiv
              ) d
              pivot 
              (
                  max(value)
                  for col in (' + @cols + ')
              ) p '

--print @query
execute(@query);

等待您的帮助!


问题答案:

您可以通过几种方法来执行此操作。

如果您有已知数量的问题/答案,则可以将其row_number()与聚合函数和CASE表达式一起使用:

select id,
  max(case when rn = 1 then question end) question1,
  max(case when rn = 1 then answer end) answer1,
  max(case when rn = 2 then question end) question2,
  max(case when rn = 2 then answer end) answer2,
  max(case when rn = 3 then question end) question3,
  max(case when rn = 3 then answer end) answer3
from
(
  select id, question, answer,
    row_number() over(partition by id order by id, question) rn
  from yt
) src
group by id;

参见带有演示的SQL Fiddle

另一个建议是同时使用UNPIVOT和PIVOT函数来获得结果。UNPIVOT将使用您的questionanswer列,并将它们转换为多行。

UNPIVOT的基本语法为:

select id,
  col+cast(rn as varchar(10)) col,
  value
from
(
  -- when you perform an unpivot the datatypes have to be the same. 
  -- you might have to cast the datatypes in this query
  select id, question, cast(answer as varchar(500)) answer,
    row_number() over(partition by id order by id, question) rn
  from yt
) src
unpivot
(
  value
  for col in (question, answer)
) unpiv;

参见演示。结果如下:

|      ID |       COL |                                VALUE |
--------------------------------------------------------------
| 4482515 | question1 | I would like to be informed by mail. |
| 4482515 |   answer1 |                                   No |
| 4482515 | question2 |                    Plan to Purchase? |
| 4482515 |   answer2 |                       Over 12 months |
| 4482515 | question3 |                   Test Question Text |
| 4482515 |   answer3 |                          some Answer |

如您所见,我row_number()在初始子查询中添加了一个值,以便您可以将每个答案与该问题相关联。一旦取消透视,您就可以将结果与question/answer连为一体的行号值在新的列名称上进行透视。具有PIVOT语法的代码将是:

select id, question1, answer1, question2, answer2,
  question3, answer3
from
(
  select id,
    col+cast(rn as varchar(10)) col,
    value
  from
  (
  -- when you perform an unpivot the datatypes have to be the same. 
  -- you might have to cast the datatypes in this query
    select id, question, cast(answer as varchar(500)) answer,
      row_number() over(partition by id order by id, question) rn
    from yt
  ) src
  unpivot
  (
    value
    for col in (question, answer)
  ) unpiv
) d
pivot
(
  max(value)
  for col in (question1, answer1, question2, answer2,
              question3, answer3)
) piv;

请参阅带有演示的SQL
Fiddle
。现在,根据您的情况,您表示将有数量众多的问题/答案。如果是这种情况,那么您将需要使用动态SQL来获取结果:

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

select @cols = STUFF((SELECT ',' + QUOTENAME(c.col+cast(rn as varchar(10))) 
                    from 
                    (
                      select row_number() over(partition by id 
                                               order by id, question) rn
                      from yt
                    ) d
                    cross apply
                    (
                      select 'question' col, 1 sort union all select 'answer', 2
                    ) c
                    group by col, rn, sort
                    order by rn, sort
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT id, ' + @cols + '
              from
              (
                select id,
                  col+cast(rn as varchar(10)) col,
                  value
                from
                (
                 -- when you perform an unpivot the datatypes have to be the same. 
                 -- you might have to cast the datatypes in this query
                  select id, question, cast(answer as varchar(500)) answer,
                    row_number() over(partition by id order by id, question) rn
                  from yt
                ) src
                unpivot
                (
                  value
                  for col in (question, answer)
                ) unpiv
              ) d
              pivot 
              (
                  max(value)
                  for col in (' + @cols + ')
              ) p '

execute(@query);

请参阅带有演示的SQL Fiddle。这些给出了结果:

|      ID |                            QUESTION1 | ANSWER1 |         QUESTION2 |        ANSWER2 |          QUESTION3 |     ANSWER3 |
------------------------------------------------------------------------------------------------------------------------------------
| 4482515 | I would like to be informed by mail. |      No | Plan to Purchase? | Over 12 months | Test Question Text | some Answer |


 类似资料:
  • 我被一个非常琐碎的问题困扰了两天。我正在创建一个带有Restendpoint的spring boot项目。有两个实体类-Employee和Address,其中一个映射为OneToMany,一个Employee具有地址列表。我创建了一个EmployeeRepository类,该类实现了JpaRepository,用于执行与员工相关的事务。因此,需要通过地址id获取员工,因此根据我的理解,如果我们必须

  • 问题内容: 如何在存储过程中获取特定数据库的数据库名称。 问题答案: 要获取当前的数据库名称,请使用。 DB_NAME(Transact-SQL)

  • 问题内容: 如标题中所指定,我想在sqlserver中获取数据库名称,我所知道的所有信息都是数据源名称,用于获取Connection对象的登录名/密码,请在Java中显示一些有关如何正确检索数据库名称的指针,谢谢! 甚至 问题答案: 从连接对象获取一个实例。 数据库名称可以通过或方法获得(取决于JDBC驱动程序的供应商)。 或使用或方法。 如果您有兴趣获得Oracle数据库服务器或Oracle数据

  • 问题内容: 我们有一个Angular应用程序,该应用程序获取一些输入参数,并将其发送到后端进行处理。处理结果是一个我们要在新选项卡中打开的pdf文件。 这样做的代码如下所示: 一切正常,但浏览器中的URL显示一些随机生成的字符串,如下所示: 显然,这对于最终用户来说看起来不太好,我们希望显示一些对用户有意义的内容,例如: 我是JS的新手,Angular的新手,HTML的新手,希望我的问题听起来不是

  • 问题内容: 我正在尝试使用BCP将存储过程导出到.csv文件。它确实为我提供了.CSV格式的输出文件,但它不显示列名。下面是脚本。请看看,让我知道我在想什么 问题答案: 经过大量的跟踪和错误之后,下面是有关如何添加列的答案 首先创建一个header.txt文件(在头文件中添加所有头文件),例如,如果头文件需要名字,姓氏等 第二,将以下查询粘贴到您的存储过程中

  • 问题内容: 我有一张有栏的桌子。数据就像 我想像下面这样安排它: 使用unpivot,我能够正确获取Name,Marks,但无法将源表中的列名获取到所需结果集中的列。 我怎样才能做到这一点? 到目前为止,我已经达到以下查询(获取名称,商标) 问题答案: 您的查询非常接近。您应该能够使用以下内容,其中包括最终选择列表中的内容: 参见带有演示的SQL Fiddle