How to join row values to column names in a dynamic query

22,055

First things first, your Answers table is terribly designed. That table is not normalized which is going to cause you problems when you want to return data. If possible, you need to restructure that table.

If you cannot redesign the table, then you will have to unpivot the answers table to be able to easily join the answers to the the questions.

An UNPIVOT will take your columns and convert them into rows. The unpivot code will be:

select formid, RecordId, answer, answercol
from answers a
unpivot
(
  answer
  for answerCol in ([Answer01], [Answer02], [Answer03], 
                    [Answer04], [Answer05], [Answer06])
) unpiv;

See SQL Fiddle with Demo. This gives a result:

| FORMID | RECORDID |         ANSWER | ANSWERCOL |
--------------------------------------------------
|      1 |        1 |      Bob Smith |  Answer01 |
|      1 |        1 |   Bobs Address |  Answer02 |
|      1 |        1 |   01234 111222 |  Answer03 |
|      1 |        1 |  [email protected] |  Answer04 |

Once the data is in rows, then you can join the questions table to return the result that you want:

select q.questiontext, d.answer
from questions q
inner join
(
  select formid, RecordId, answer, answercol
  from answers a
  unpivot
  (
    answer
    for answerCol in ([Answer01], [Answer02], [Answer03], 
                      [Answer04], [Answer05], [Answer06])
  ) unpiv
) d
  on q.AnswerField = d.answercol
  and q.formid = d.formid
where d.recordid = 1;

See SQL Fiddle with Demo. This gives a result:

| QUESTIONTEXT |        ANSWER |
--------------------------------
|         Name |     Bob Smith |
|      Address |  Bobs Address |
|        Phone |  01234 111222 |
|        Email | [email protected] |
Share:
22,055
Yetiish
Author by

Yetiish

Updated on June 18, 2020

Comments

  • Yetiish
    Yetiish almost 4 years

    I am developing an application that allows configurable questions and answers. Currently there can be up to 20 answers, but possibly less.

    The structure I have is as follows:

    Questions

    +----+--------+--------------+-------------+
    | ID | FormId | QuestionText | AnswerField |
    +----+--------+--------------+-------------+
    |  1 |      1 | Name         | Answer01    |
    |  2 |      1 | Address      | Answer02    |
    |  3 |      1 | Phone        | Answer03    |
    |  4 |      1 | Email        | Answer04    |
    |  5 |      2 | First Name   | Answer01    |
    |  6 |      2 | Surname      | Answer02    |
    +----+--------+--------------+-------------+
    

    Answers

    +----+--------+----------+------------+--------------+--------------+----------------+----------+----------+
    | ID | FormId | RecordId |  Answer01  |   Answer02   |   Answer03   |    Answer04    | Answer05 | Answer06 |
    +----+--------+----------+------------+--------------+--------------+----------------+----------+----------+
    |  1 |      1 |        1 | Bob Smith  | Bobs Address | 01234 111222 | [email protected]  | Null     | Null     |
    |  2 |      1 |        2 | Joe Bloggs | Joes Address | 04321 333444 | [email protected] | Null     | Null     |
    |  3 |      2 |        3 | David      | Jones        | Null         | Null           | Null     |          |
    +----+--------+----------+------------+--------------+--------------+----------------+----------+----------+
    

    So in the Questions table AnswerField Answer01 maps to the Answer01 column in the Answers table

    What I would like to do is get a result set that looks something like:

    For form ID 1 & record ID 1:

    +--------------+---------------+
    | QuestionText |    Answer     |
    +--------------+---------------+
    | Name         | Bob Smith     |
    | Address      | Bobs Address  |
    | Phone        | 01234 111222  |
    | Email        | [email protected] |
    +--------------+---------------+
    

    Then for form id 2 & record id 3:

    +--------------+---------+
    | QuestionText | Answer  |
    +--------------+---------+
    | First Name   | David   |
    | Surname      | Jones   |
    +--------------+---------+
    

    I have tried using a pivot table:

    SELECT QuestionText, Answer01, Answer02, Answer03, Answer04
    FROM (
        SELECT DISTINCT Q.AnswerField, Q.QuestionText, Q.ID, A.Answer01, A.Answer02, A.Answer03, A.Answer04
        FROM Questions Q
        INNER JOIN Answers A ON A.FormId= Q.FormId
        WHERE A.ID = 17
    ) 
    AS src
    PIVOT (MAX(question_id) FOR Answer IN(answer_01, answer_02, answer_03, answer_04)) AS pvt
    

    But this repeats the answers in all columns:

    +--------------+-----------+--------------+--------------+---------------+
    | QuestionText | Answer01  |   Answer02   |   Answer03   |   Answer04    |
    +--------------+-----------+--------------+--------------+---------------+
    | Name         | Bob smith | Bobs Address | 01234 111222 | [email protected] |
    | Address      | Bob smith | Bobs Address | 01234 111222 | [email protected] |
    | Phone        | Bob smith | Bobs Address | 01234 111222 | [email protected] |
    | Email        | Bob smith | Bobs Address | 01234 111222 | [email protected] |
    +--------------+-----------+--------------+--------------+---------------+
    

    Which obviously isn't right.

    Can anyone suggest how this might be done in a SQL Server stored procedure please?