0

我认为通过示例来展示会是最快的,所以这里有一个我的问题的简化版本。我正在使用 SQL Server。

这是数据模型

SURVEY       QUESTION        ANSWER
------       --------        -------
surveyId     questionId      answerId
             questionText    surveyId
                             questionId
                             answerText

这是一些示例数据

SURVEY          QUESTION
 ----------      ------------ --------------
| surveyId |    | questionId | questionText |
 ----------      ------------ --------------
| 1        |    | 1          | Name         |
| 2        |    | 2          | E-Mail       |
 ----------     | 3          | Address      |
                | 4          | Phone        |
                 ------------ --------------
ANSWER
 -----------------------------------------------
| answerId | surveyId | questionId | answerText |
 -----------------------------------------------
| 1        | 1        | 1          | John       |
| 2        | 1        | 2          | john@aa.bb |
| 3        | 1        | 3          | New York   |
| 4        | 1        | 4          | 1112223344 |
| 5        | 2        | 1          | Pete       |
| 6        | 2        | 2          | pete@cc.dd |
| 7        | 2        | 3          | Boston     |
| 8        | 2        | 4          | 5556667788 |
 -----------------------------------------------

最后,这是我要选择的

RESULT
 ------------------------------
| surveyId | name | email      |
 ------------------------------
| 1        | John | john@aa.bb |
| 2        | Pete | pete@dd.cc |
 ------------------------------

我希望能够在运行时指定最终表格中需要哪些列。现在我可以通过执行以下操作得到这个结果

SELECT rName.surveyId, rName.requestor, rEmail.email 
FROM (SELECT a.answerText AS name, a.surveyId
      FROM answer a INNER JOIN question q ON a.questionId = q.questionId 
      WHERE a.surveyId = @surveyId AND q.questionText = 'Name') AS rName
INNER JOIN 
     (SELECT a.answerText AS name, a.surveyId
      FROM answer a INNER JOIN question q ON a.questionId = q.questionId 
      WHERE a.surveyId = @surveyId AND q.questionText = 'E-Mail') AS rEmail
ON rName.questionnaireId = rEmail.questionnaireId

如您所见,它很丑陋,并且包含重复的代码。有没有办法做这个清洁?

4

4 回答 4

2
SELECT  a.surveyID,
        MAX(CASE WHEN c.questionText = 'Name' THEN b.answerText ELSE NULL END) name,
        MAX(CASE WHEN c.questionText = 'E-Mail' THEN b.answerText ELSE NULL END) email
FROM    Survey a
        INNER JOIN Answer b
            ON a.surveyID = b.surveyID
        INNER JOIN Question c
            ON b.questionID = c.questionID
GROUP BY a.surveyID
于 2012-11-01T13:01:51.233 回答
2

SQL Server 具有PIVOT可用于此类查询的函数。如果您知道要转换的值,则可以对这些值进行硬编码:

select surveyid, name, [e-mail]
from
(
  select a.answertext,
    q.questiontext,
    s.surveyid
  from survey s
  left join answer a
    on s.surveyid = a.surveyid
  left join question q
    on a.questionid = q.questionid
) src
pivot
(
  max(answertext)
  for questiontext in ([name], [e-mail])
) p

请参阅带有演示的 SQL Fiddle

现在,如果您有未知数量的值,则可以pivot对数据使用动态 sql:

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

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(questiontext) 
                    from question
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT surveyid, ' + @cols + ' from 
             (
                select a.answertext,
                  q.questiontext,
                  s.surveyid
                from survey s
                left join answer a
                  on s.surveyid = a.surveyid
                left join question q
                  on a.questionid = q.questionid
            ) x
            pivot 
            (
                max(answertext)
                for questiontext in (' + @cols + ')
            ) p '

execute(@query)

请参阅带有演示的 SQL Fiddle

于 2012-11-01T13:11:40.950 回答
2

SQL 提琴示例

select *
from
(
  select
      s.surveyid,
      q.questionText,
      a.answerText
  from SURVEY as s
      cross join QUESTION as q
      left outer join ANSWER as a on a.questionId = q.questionId and a.surveyId = s.SurveyId
) as M
pivot
(
  min(M.answerText)
  for M.questionText in ([Name], [E-Mail], [Address], [Phone])
) as P
于 2012-11-01T13:16:01.930 回答
1

可能不是 PIVOT 的“正确”用法,但以下方法可以解决问题(req. SQL2005 或更高版本):

SELECT surveryId, [1] AS [name], [2] AS [e-mail]
FROM 
( SELECT a.surveryId, q.QuestionId, a.answerText
FROM dbo.Question q
INNER JOIN dbo.Answer a ON a.questionId = q.QuestionId
) tmp
PIVOT (
    MAX(answerText)
    FOR questionId IN ([1], [2])
) PvtTable
于 2012-11-01T13:19:42.023 回答