sql-server-2008 - 通过分组将行选择到列中

标签 sql-server-2008 t-sql

我有几张 table :

     Exams 
     UserExams 
     UserExamQuestions 
     UserExamAnswers 
     Users 
     ExamQuestions 
     ExamQuestionAnswers

这是我开发的选择

    select ue.DateStarted as 'Date Started', u.LastName as 'Lastname', 
    u.FirstName as 'Firstname', eq.Text as 'Question', eqa.Text as 'Answer',
    eqa.IsCorrect as 'Correct' from Exams e
    join UserExams ue on ue.ExamId = e.Id
    join UserExamQuestions ueq on ueq.UserExamId = ue.Id
    join UserExamAnswers uea on uea.UserExamQuestionId = ueq.Id
    join Users u on u.Id = ue.UserId
    join ExamQuestions eq on eq.Id = ueq.ExamQuestionId
    join ExamQuestionAnswers eqa on eqa.Id = uea.ExamQuestionAnswerId
    where e.Id = 10 and uea.IsSelected = 1
    order by u.LastName, u.FirstName

但不幸的是它以不需要的方式返回数据。返回的行看起来像这样

    Date Started            Lastname  Firstname      Question             Answer         Correct
    2012-02-26 13:29:50.770 Somename  Somefirstname  Some question text?  Some answer   0
    2012-02-26 13:30:20.000 Othername Otherfirstname Some question text?  Some answer   0
    2012-02-26 15:10:10.212 Fifth     Fifthname      Some question text?  Other answer  1

当然,上面的例子是针对三个用户的,他们回答了一个问题并给出了一些答案。选定的数据很好,但我需要它是这样的:

   Lastname  Firstname       [Some question text?] Correct
   Somename  Somefirstname   Some answer           0
   Othername Otherfirstname  Some answer           0
   Fifth     Fifthname       Other answer          1

这可能吗?它不必很快。在代码后面执行此操作会很痛苦...我正在尝试枢轴,但首先 - 我认为我没有正确理解它,其次我不想聚合数据。

感谢您的帮助。

最佳答案

好的。所以我确实看到你的回答,我给你一个建议。当您说要使用枢轴来完成此操作时,您实际上是正确的。

所以首先我出于测试目的简化了您的数据。测试数据如下:

CREATE TABLE Table1
(
    Lastname VARCHAR(100),  
    Firstname VARCHAR(100),
    Answer VARCHAR(100),
    Question VARCHAR(100),
    Correct BIT
)
INSERT INTO Table1
VALUES
  ('Somename','Somefirstname','Some answer','Some question text?',0),
  ('Somename','Somefirstname','Answer to second question','Second question in same column?',1),
  ('Othername','Otherfirstname','Some answer','Some question text?',0),
  ('Othername','Otherfirstname','Wrong answer to second question','Second question in same column?',0),
  ('Fifth','Fifthname','Other answer','Some question text?',1),
  ('Fifth','Fifthname','Wrong answer to second question','Second question in same column?',0)

您需要获取要依赖的唯一列。像这样:

DECLARE @Questions VARCHAR(MAX)
;WITH CTE
AS
(
  SELECT
    ROW_NUMBER() OVER(PARTITION BY Question ORDER BY Question) AS RowNbr,
    ROW_NUMBER() OVER(ORDER BY Question) AS OrderBy,
    Table1.Question
  FROM
    Table1
), CTE2
AS
(
  SELECT
    CTE.OrderBy AS OrderBy,
    1 AS SecondOrder,
    CTE.Question
  FROM
    CTE
  WHERE
    CTE.RowNbr=1
  UNION ALL
  SELECT
    CTE.OrderBy AS OrderBy,
    2 AS SecondOrder,
    'Is '+CTE.Question
  FROM
    CTE
  WHERE
    CTE.RowNbr=1
)
SELECT
  @Questions = COALESCE(@Questions + ','+QUOTENAME(Question),
                     QUOTENAME(Question))
FROM
  CTE2
ORDER BY
  CTE2.OrderBy,
  CTE2.SecondOrder
  • 第一个ROW_NUMBER() OVER(PARTITION BY Question ORDER BY Question)用于获取唯一列。稍后我将在 where 语句中使用它。

  • 第二个ROW_NUMBER() OVER(ORDER BY Question)是对问题进行排序

  • SecondOrder 是为了让您将该问题排序在“Is”问题之前

  • UNION ALL 是为了让我们能够 UNION ALL 问题和"is"问题

  • @Questions = COALESCE(@Questions + ','+QUOTENAME(Question),.. 将各列连接到一个 varchar

然后我们需要为pivot创建一些动态sql并在最后执行它。像这样:

DECLARE @query NVARCHAR(4000)=
N';WITH CTE
AS
(
  SELECT
    Table1.Lastname,
    Table1.Firstname,
    Table1.Answer,
    Table1.Question
  FROM
    Table1
  UNION ALL
  SELECT
    Table1.Lastname,
    Table1.Firstname,
    CAST(Table1.Correct AS VARCHAR(10)) AS Answer,
    ''Is ''+Table1.Question AS Question
  FROM
    Table1
)
SELECT
  *
FROM
(
  SELECT
    CTE.Lastname,
    CTE.Firstname,
    CTE.Answer,
    CTE.Question
  FROM
    CTE
) AS p
PIVOT
(
    MAX(Answer)
    FOR Question IN ('+@Questions+')
) AS pvt'
EXECUTE(@query)
  • 然后我们需要将问题与“Is”问题UNION ALL

  • 正确列被转换为VARCHAR,因为UNION ALL和数据透视不允许不同的数据类型

  • 我们将使用 MAX 聚合来获取我们需要的答案。这是因为数据透视表要求我们使用聚合。

  • FOR Question IN ('+@Questions+') 是我们在上面的查询中连接的列。

可以看到结果和示例数据here

希望这对你有帮助

关于sql-server-2008 - 通过分组将行选择到列中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9625339/

相关文章:

sql-server - TSQL - Select 中的 While 循环?

sql - 为可为空的字段添加默认值 NULL 是否毫无意义

T-SQL 2012,While 循环最大迭代次数?

sql server 2008 Management Studio 不检查我的查询的语法

c# - sql server 2008 企业版建议保留多少开放连接

sql - 动态SQL - 根据参数查询不同的数据库

sql - 在 SQL Server 中查找并拆分

sql - 如何在查询中选择包含多个项目的组?

c++ - 如何在 QT[C++] 中从 linux 机器连接 SQL Server 2008 R2?

sql-server - 是否有内置方法将 sql server 中的列限制为表设计 View 中的显式值列表?