简体   繁体   中英

Join multiple values from one column, selected from another table

Given these simplified multiple choice tables where sometimes more than one answer is correct:

STUDENT_ANSWERS
AnswerID | StudentID | QuestionID | Answers
-------------------------------------------
       1 |         1 |          1 | C,D

QUESTION_ANSWERS
QuestionID | Answer | Text
-------------------------------------------------
         1 |      A | This is answer A
         1 |      B | B could also be correct
         1 |      C | Maybe it's C?
         1 |      D | Definitely D!

How do I do a select which translates the answers to their descriptions?

My start:

SELECT *
FROM STUDENT_ANSWERS sa
LEFT OUTER JOIN QUESTION_ANSWERS qa ON qa.Answer IN sa.Answers???
 -- Doesn't seem to work as IN requires a format of ('C','D') while I have 'C,D'

Desired output:

AnswerID | StudentID | QuestionID | AnswerDescriptions
-------------------------------------------
       1 |         1 |          1 | Maybe it's C?,Definitely D!

So the descriptions simply have to replace the codes instead of getting a single line for each answer.

Your problem is the structure of table STUDENT_ANSWERS . It should have one row per answer:

AnswerID | StudentID | QuestionID | Answer
-------------------------------------------
       1 |         1 |          1 | C
       2 |         1 |          1 | D

Now, assuming you can't do anything to change (read: fix) this, you can fudge it with appending a comma and using LIKE:

select *
from STUDENT_ANSWERS a
join QUESTION_ANSWERS q on ',' + a.Answers + ',' like '%,' + q.Answer + ',%'
    and a.QuestionID = q.QuestionID

SQL Fiddle demo

Note this assumes you will never ever have the text , in QUESTION_ANSWERS.Answer . It will also never be able to use an index, so it's going to be slower than slow.

And if you absolutely must format this in the database to be one line, you can use STUFF and the FOR XML PATH('') trick to concatenate the resulting rows.

This is full working example using only T-SQL statements. I will recommend to you to create separate function for splitting CSV that returns row set. Also, if you are working with huge amount of data, you may want to create a CLR function for splitting the values. Take a look to this article (there is everything you need).

DECLARE @StudentAnswers TABLE
(
     [AnswerID] INT
    ,[StudentID] INT
    ,[QuestionID] INT
    ,[Answers] VARCHAR(256)
);

DECLARE @QuestionAnswers TABLE
(
     [QuestionID] INT
    ,[Answer] CHAR
    ,[Text] VARCHAR(256)
);

INSERT INTO @StudentAnswers ([AnswerID], [StudentID], [QuestionID], [Answers])
VALUES (1, 1, 1, 'C,D')
      ,(2, 2, 1, 'A');

 INSERT INTO @QuestionAnswers ([QuestionID], [Answer], [Text])
 VALUES  (1, 'A', 'This is answer A')
        ,(1, 'B', 'B could also be correct')
        ,(1, 'C', 'Maybe it''s C?')
        ,(1, 'D', 'Definitely D!');

SELECT SA.[AnswerID]
      ,SA.[StudentID]
      ,SA.[QuestionID]
      ,T.c.value('.', 'CHAR')
      ,QA.[Text]
FROM @StudentAnswers SA
CROSS APPLY 
(
    SELECT CAST('<i>' + REPLACE([Answers], ',', '</i><i>') + '</i>' AS XML) Answers
) DS
CROSS APPLY DS.Answers.nodes('i') T(c)
INNER JOIN @QuestionAnswers QA
    ON SA.[QuestionID] = QA.[QuestionID]
    AND T.c.value('.', 'CHAR') = QA.[Answer];

Try this

select answerid,studentid,a.QuestionID,group_concat(b.text) from student_answers a left join QUESTION_ANSWERS b on b.questionid= a.questionid and  FIND_IN_SET(b.Answer, a.Answers)
group by a.questionid

Definitely it works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM