I know how to join an XML variable to other tables, but in this case, I am trying to select each row from a table plus the structure of the XML from each respective table row, alongside that row. I cannot find any examples online to help with this, as most examples deal with a single XML value (apologies if there are, I was unable to locate them in amongst the myriad of other XML examples).
The table structure is this:
CREATE TABLE tbl_QuizHistory (
HistoryId int PRIMARY KEY,
QuizData xml NOT NULL
);
Each QuizData
row value is similar to this:
<quizresult>
<question>
<questionText>Which fire extinguisher is most suitable for a waste paper basket fire?</questionText>
<answer number="0" value="0" chosen="0" imageURL="">Powder</answer>
<answer number="1" value="0" chosen="0" imageURL="">Carbon Dioxide (CO2)</answer>
<answer number="2" value="1" chosen="1" imageURL="">Water (H2O)</answer>
<answer number="3" value="0" chosen="0" imageURL="">Foam</answer>
<result>Correct</result>
</question>
<question>
<questionText>Should you use lifts during a fire?</questionText>
<answer number="0" value="0" chosen="0" imageURL="">Yes</answer>
<answer number="1" value="1" chosen="1" imageURL="">No</answer>
<result>Correct</result>
</question>
</quizresult>
In an earlier question I was shown how to display the XML data hierarchically (@xml ==> questions ==> answer(s)
), but only for a single XML value, which I adapted to migrate the question/answer hierarchy into a table:
-- Works for a single XML value/variable...
;WITH q AS (
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS qID,
n.q.value('(./questionText)[1]', 'nvarchar(max)') AS questionText,
n.q.value('(./result)[1]', 'nvarchar(50)') AS result,
n.q.query('answer') AS answers
FROM
@xml.nodes('/quizresult/question') AS n (q)
),
qa AS (
SELECT
qID,
questionText,
result,
answer.query('.') AS answer
FROM
q CROSS APPLY
answers.nodes('answer') AS a(answer)
)
SELECT
qa.qID,
q.questionText,
q.result,
qa.answer.value('answer[1]', 'nvarchar(max)') AS answer,
qa.answer.value('answer[1]/@number', 'int') AS number,
qa.answer.value('answer[1]/@value', 'int') AS val,
qa.answer.value('answer[1]/@chosen', 'bit') AS chosen
FROM
qa INNER JOIN
q ON qa.qID = q.qID;
How can this logic be applied to every XML value, in every table row? I need to display
- The quiz HistoryId
- Each question from that quiz (with optional ID for clarity, although this was generated by the SQL statement, and doesn't exist in the XML)
- All the answers for each question
The end result I am trying to achieve would produce something like this:
HistoryId qID questionText result answer number val chosen
--------- ---- --------------------------------------------------------------------------------------- ---------- ---------------------------------------------------------------------------------------- ------- ---- ------
100 1 Which fire extinguisher is most suitable for a waste paper basket fire? Correct Powder 0 0 0
100 1 Which fire extinguisher is most suitable for a waste paper basket fire? Correct Carbon Dioxide (CO2) 1 0 0
100 1 Which fire extinguisher is most suitable for a waste paper basket fire? Correct Water (H2O) 2 1 1
100 1 Which fire extinguisher is most suitable for a waste paper basket fire? Correct Foam 3 0 0
100 2 What should your immediate action be on hearing a fire alarm? Correct Find all of your colleagues before making a speedy exit together 0 0 0
100 2 What should your immediate action be on hearing a fire alarm? Correct Collect all your valuables before making a speedy exit 1 0 0
100 2 What should your immediate action be on hearing a fire alarm? Correct Check the weather to see if you need your coat before leaving 2 0 0
100 2 What should your immediate action be on hearing a fire alarm? Correct Leave the building by the nearest exit, closing doors behind you if the rooms are empty 3 1 1
101 1 Which fire extinguisher is most suitable for a waste paper basket fire? Correct Powder 0 0 0
101 1 Which fire extinguisher is most suitable for a waste paper basket fire? Correct Carbon Dioxide (CO2) 1 0 0
101 1 Which fire extinguisher is most suitable for a waste paper basket fire? Correct Water (H2O) 2 1 1
101 1 Which fire extinguisher is most suitable for a waste paper basket fire? Correct Foam 3 0 0
101 2 Should you use lifts during a fire? Correct Yes 0 0 0
101 2 Should you use lifts during a fire? Correct No 1 1 1
101 3 Which part of a Carbon Dioxide (CO2) extinguisher should you not touch when operating? Incorrect The body of the extinguisher 0 0 1
101 3 Which part of a Carbon Dioxide (CO2) extinguisher should you not touch when operating? Incorrect The release trigger and the bottom of the extinguisher 1 0 0
101 3 Which part of a Carbon Dioxide (CO2) extinguisher should you not touch when operating? Incorrect The horn of the extinguisher 2 1 0
I appreciate that this creates a large number of duplication (as the questions are repeated for each answer), but that's okay.
I have a SQL Fiddle which I've been working from, with sample data set up.