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

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 に答える
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 FiddlewithDemoを参照してください

これで、値の数が不明な場合は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 FiddlewithDemoを参照してください

于 2012-11-01T13:11:40.950 に答える
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 に答える
1

PIVOTの「正しい」使用法ではない可能性がありますが、次の方法でうまくいきます(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 に答える