|
|
|
Forum Newbie
      
Group: General Forum Members
Last Login: Monday, February 04, 2013 6:51 AM
Points: 7,
Visits: 22
|
|
I am trying to generate a report showing which questions were missed on an online test for a given student. Can someone help me with this?
The report should look something like:
Megan missed the following questions: 1. Capitol of California 4. Capitol of Idaho 5. Capitol of Nevada
Here are the tables...
CREATE TABLE Tests( ID [bigint] IDENTITY(1,1) NOT NULL, UserID [varchar](10) NOT NULL, TQ1 [int] NULL, TA1 [int] NULL, TQ2 [int] NULL, TA2 [int] NULL, TQ3 [int] NULL, TA3 [int] NULL, TQ4 [int] NULL, TA4 [int] NULL, TQ5 [int] NULL, TA5 [int] NULL)
INSERT INTO Tests (UserID,TQ1,TA1,TQ2,TA2,TQ3,TA3,TQ4,TA4,TQ5,TA5) VALUES ('John',6,2,8,3,2,2,10,1,5,4) INSERT INTO Tests (UserID,TQ1,TA1,TQ2,TA2,TQ3,TA3,TQ4,TA4,TQ5,TA5) VALUES ('Megan',3,1,8,3,7,4,9,2,6,3) INSERT INTO Tests (UserID,TQ1,TA1,TQ2,TA2,TQ3,TA3,TQ4,TA4,TQ5,TA5) VALUES ('David',2,2,3,2,10,2,5,3,6,1) INSERT INTO Tests (UserID,TQ1,TA1,TQ2,TA2,TQ3,TA3,TQ4,TA4,TQ5,TA5) VALUES ('Suzan',10,4,4,3,1,5,8,2,9,1) INSERT INTO Tests (UserID,TQ1,TA1,TQ2,TA2,TQ3,TA3,TQ4,TA4,TQ5,TA5) VALUES ('Robert',1,3,6,1,2,3,4,1,5,4) INSERT INTO Tests (UserID,TQ1,TA1,TQ2,TA2,TQ3,TA3,TQ4,TA4,TQ5,TA5) VALUES ('Keith',3,3,2,2,10,1,7,4,8,2)
CREATE TABLE QuestionList( ID [int] NULL, Question [varchar](50) NOT NULL, Answer1 [varchar](50) NULL, IsCorrect1 [bit] NULL, Answer2 [varchar](50) NULL, IsCorrect2 [bit] NULL, Answer3 [varchar](50) NULL, IsCorrect3 [bit] NULL, Answer4 [varchar](50) NULL, IsCorrect4 [bit] NULL, Answer5 [varchar](50) NULL, IsCorrect5 [bit] NULL)
INSERT INTO QuestionList (ID,Question,Answer1,IsCorrect1,Answer2,IsCorrect2,Answer3,IsCorrect3,Answer4,IsCorrect4,Answer5,IsCorrect5) VALUES(1,'Capital of Texas?','Houston',0,'San Antonio',0,'Austin',1,'Amarillo',0,'Dallas',0) INSERT INTO QuestionList (ID,Question,Answer1,IsCorrect1,Answer2,IsCorrect2,Answer3,IsCorrect3,Answer4,IsCorrect4) VALUES(2,'Capital of Florida?','Tallahassee',1,'Miami',0,'Jacksonville',0,'Tampa',0) INSERT INTO QuestionList (ID,Question,Answer1,IsCorrect1,Answer2,IsCorrect2,Answer3,IsCorrect3,Answer4,IsCorrect4) VALUES(3,'Capital of California?','Bakersfield',0,'San Diego',0,'Los Angeles',0,'Sacramento',1) INSERT INTO QuestionList (ID,Question,Answer1,IsCorrect1,Answer2,IsCorrect2,Answer3,IsCorrect3,Answer4,IsCorrect4) VALUES(4,'Capital of New York?','New York',0,'Albany',1,'Rochester',0,'Syracuse',0) INSERT INTO QuestionList (ID,Question,Answer1,IsCorrect1,Answer2,IsCorrect2,Answer3,IsCorrect3,Answer4,IsCorrect4) VALUES(5,'Capital of Oklahoma?','Norman',0,'Oklahoma City',1,'Tulsa',0,'Duncanville',0) INSERT INTO QuestionList (ID,Question,Answer1,IsCorrect1,Answer2,IsCorrect2,Answer3,IsCorrect3) VALUES(6,'Capital of Nevada?','Carson City',1,'Las Vegas',0,'Reno',0) INSERT INTO QuestionList (ID,Question,Answer1,IsCorrect1,Answer2,IsCorrect2,Answer3,IsCorrect3,Answer4,IsCorrect4) VALUES(7,'Capital of Ohio?','Cleveland',0,'Toledo',0,'Dayton',0,'Columbus',1) INSERT INTO QuestionList (ID,Question,Answer1,IsCorrect1,Answer2,IsCorrect2,Answer3,IsCorrect3,Answer4,IsCorrect4) VALUES(8,'Capital of Georgia?','Augusta',0,'Columbus',0,'Atlanta',1,'Athens',0) INSERT INTO QuestionList (ID,Question,Answer1,IsCorrect1,Answer2,IsCorrect2,Answer3,IsCorrect3,Answer4,IsCorrect4) VALUES(9,'Capital of Idaho?','Boise',1,'Caldwell',0,'Dubois',0,'Idaho City',0) INSERT INTO QuestionList (ID,Question,Answer1,IsCorrect1,Answer2,IsCorrect2,Answer3,IsCorrect3,Answer4,IsCorrect4) VALUES(10,'Capital of Michigan?','Detroit',0,'Lansing',1,'Grand Rapids',0,'Dearborn',0)
|
|
|
|
|
SSCertifiable
       
Group: General Forum Members
Last Login: Today @ 8:35 PM
Points: 6,694,
Visits: 11,709
|
|
Looks like homework, which is fine, I am happy to help, but please show us what have you tried so far?
PS Thank you for providing consumable DDL and DML so we can setup a test environment on our side. You would be surprised how many people do not bother when asking for help.
__________________________________________________________________________________________________ There are no special teachers of virtue, because virtue is taught by the whole community. --Plato
Believe you can and you're halfway there. --Theodore Roosevelt
Everything Should Be Made as Simple as Possible, But Not Simpler --Albert Einstein
The significant problems we face cannot be solved at the same level of thinking we were at when we created them. --Albert Einstein
1 apple is not exactly 1/8 of 8 apples. Because there are no absolutely identical apples. --Giordy
|
|
|
|
|
Forum Newbie
      
Group: General Forum Members
Last Login: Monday, February 04, 2013 6:51 AM
Points: 7,
Visits: 22
|
|
| Not homework, actual website. I greatly simplified the sample tables for clarity. The website (thspa.us) provides online testing of the judges used at powerlifting meets. I am able to generate the judges tests and score them, but I need to provide a list of the questions they missed. The test is 50 questions long and can take as long as an hour to complete, and simply telling them how many questions they missed is causing some testing anxiety. I've tried several ways, including reformatting the data into a temporary table. I'm working now on using PIVOT and UNPIVOT (just found out about those yesterday). I'll see how far I get.
|
|
|
|
|
SSCertifiable
       
Group: General Forum Members
Last Login: Today @ 8:35 PM
Points: 6,694,
Visits: 11,709
|
|
This is unpivoting multiple columns. See how these results look:
WITH TestQuestions(Id, Question, AnswerNumber, Answer, IsCorrect) AS ( SELECT Id, Question, ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Answers) AS AnswerNumber, Answer, IsCorrect FROM ( SELECT ID, Question, Answer1, IsCorrect1, Answer2, IsCorrect2, Answer3, IsCorrect3, Answer4, IsCorrect4, Answer5, IsCorrect5 FROM dbo.QuestionList ) Main UNPIVOT ( Answer FOR Answers IN (Answer1, Answer2, Answer3, Answer4, Answer5) ) Sup UNPIVOT ( IsCorrect FOR IsCorrects IN (IsCorrect1, IsCorrect2, IsCorrect3, IsCorrect4, IsCorrect5) ) Ct WHERE RIGHT(Answers, 1) = RIGHT(IsCorrects, 1) ), TestAnswers(Id, UserID, QuestionNumber, Question, Answer) AS ( SELECT Id, UserID, ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Questions) AS QuestionNumber, Question, Answer FROM ( SELECT ID, UserID, TQ1, TQ2, TQ3, TQ4, TQ5, TA1, TA2, TA3, TA4, TA5 FROM dbo.Tests --WHERE UserID = 'David' ) Main UNPIVOT ( Question FOR Questions IN (TQ1, TQ2, TQ3, TQ4, TQ5) ) Sup UNPIVOT ( Answer FOR Answers IN (TA1, TA2, TA3, TA4, TA5) ) Ct WHERE RIGHT(Questions, 1) = RIGHT(Answers, 1) ) SELECT DISTINCT * FROM TestQuestions tq JOIN TestAnswers ta ON tq.Id = ta.Question AND tq.AnswerNumber = ta.Answer WHERE IsCorrect = 0 ORDER BY UserID, QuestionNumber;
__________________________________________________________________________________________________ There are no special teachers of virtue, because virtue is taught by the whole community. --Plato
Believe you can and you're halfway there. --Theodore Roosevelt
Everything Should Be Made as Simple as Possible, But Not Simpler --Albert Einstein
The significant problems we face cannot be solved at the same level of thinking we were at when we created them. --Albert Einstein
1 apple is not exactly 1/8 of 8 apples. Because there are no absolutely identical apples. --Giordy
|
|
|
|
|
Forum Newbie
      
Group: General Forum Members
Last Login: Monday, February 04, 2013 6:51 AM
Points: 7,
Visits: 22
|
|
| Holy crap that's good stuff! Works perfectly. I didn't expect anyone to write the whole thing. Thank you very much. Don't know how long it took you to write it but it will take me a while to break it down and figure out how it works. Several lessons in one SQL statement...
|
|
|
|
|
SSCertifiable
       
Group: General Forum Members
Last Login: Today @ 8:35 PM
Points: 6,694,
Visits: 11,709
|
|
Not a problem. I hadn't played with unpivoting data in a long time so I took it on as a learning challenge. It took me about a half hour to produce the code.
Here, however, is a much improved version that does not use UNPIVOT at all that should be easier to understand, and more importantly should scale up much better performance-wise.
IF OBJECT_ID(N'tempdb..#TestQuestionsAndAnswers') IS NOT NULL DROP TABLE #TestQuestionsAndAnswers;
IF OBJECT_ID(N'tempdb..#TestResults') IS NOT NULL DROP TABLE #TestResults;
SELECT q.Id AS QuestionID, q.Question, d.Answer, d.IsCorrect, d.AnswerID INTO #TestQuestionsAndAnswers FROM dbo.QuestionList q CROSS APPLY ( SELECT q.Answer1, q.IsCorrect1, 1 AS AnswerID UNION ALL SELECT q.Answer2, q.IsCorrect2, 2 AS AnswerID UNION ALL SELECT q.Answer3, q.IsCorrect3, 3 AS AnswerID UNION ALL SELECT q.Answer4, q.IsCorrect4, 4 AS AnswerID UNION ALL SELECT q.Answer5, q.IsCorrect5, 5 AS AnswerID ) d (Answer, IsCorrect, AnswerID) WHERE d.Answer IS NOT NULL;
SELECT t.ID AS UserUniqueID, t.UserID, d.TQ AS QuestionID, d.TA AS Answer INTO #TestResults FROM dbo.Tests t CROSS APPLY ( SELECT t.TQ1, t.TA1 UNION ALL SELECT t.TQ2, t.TA2 UNION ALL SELECT t.TQ3, t.TA3 UNION ALL SELECT t.TQ4, t.TA4 UNION ALL SELECT t.TQ5, t.TA5 ) d (TQ, TA);
SELECT * FROM #TestQuestionsAndAnswers; SELECT * FROM #TestResults; GO
SELECT * FROM #TestQuestionsAndAnswers qa JOIN #TestResults tr ON qa.QuestionID = tr.QuestionID AND qa.AnswerID = tr.Answer ORDER BY tr.UserID, qa.QuestionID;
edit: code formatting
__________________________________________________________________________________________________ There are no special teachers of virtue, because virtue is taught by the whole community. --Plato
Believe you can and you're halfway there. --Theodore Roosevelt
Everything Should Be Made as Simple as Possible, But Not Simpler --Albert Einstein
The significant problems we face cannot be solved at the same level of thinking we were at when we created them. --Albert Einstein
1 apple is not exactly 1/8 of 8 apples. Because there are no absolutely identical apples. --Giordy
|
|
|
|
|
Forum Newbie
      
Group: General Forum Members
Last Login: Monday, February 04, 2013 6:51 AM
Points: 7,
Visits: 22
|
|
| Two for the price of one...my day just keeps getting better. Thanks a bunch for the code. I do like this one better. Definitely easier to understand. While I was having a little trouble scaling the first one up for a 50 question test (plus a few other tweaks that weren't reflected in the sample tables I gave you) this went much smoother. Thanks again and have a good week...mine's starting out great.
|
|
|
|
|
SSCertifiable
       
Group: General Forum Members
Last Login: Today @ 8:35 PM
Points: 6,694,
Visits: 11,709
|
|
You're quite welcome. I am happy it helped.
__________________________________________________________________________________________________ There are no special teachers of virtue, because virtue is taught by the whole community. --Plato
Believe you can and you're halfway there. --Theodore Roosevelt
Everything Should Be Made as Simple as Possible, But Not Simpler --Albert Einstein
The significant problems we face cannot be solved at the same level of thinking we were at when we created them. --Albert Einstein
1 apple is not exactly 1/8 of 8 apples. Because there are no absolutely identical apples. --Giordy
|
|
|
|
|
SSCrazy
      
Group: General Forum Members
Last Login: Yesterday @ 12:42 AM
Points: 2,338,
Visits: 3,158
|
|
opc.three (1/12/2013)
Not a problem. I hadn't played with unpivoting data in a long time so I took it on as a learning challenge. It took me about a half hour to produce the code. Here, however, is a much improved version that does not use UNPIVOT at all that should be easier to understand, and more importantly should scale up much better performance-wise. IF OBJECT_ID(N'tempdb..#TestQuestionsAndAnswers') IS NOT NULL DROP TABLE #TestQuestionsAndAnswers;
IF OBJECT_ID(N'tempdb..#TestResults') IS NOT NULL DROP TABLE #TestResults;
SELECT q.Id AS QuestionID, q.Question, d.Answer, d.IsCorrect, d.AnswerID INTO #TestQuestionsAndAnswers FROM dbo.QuestionList q CROSS APPLY ( SELECT q.Answer1, q.IsCorrect1, 1 AS AnswerID UNION ALL SELECT q.Answer2, q.IsCorrect2, 2 AS AnswerID UNION ALL SELECT q.Answer3, q.IsCorrect3, 3 AS AnswerID UNION ALL SELECT q.Answer4, q.IsCorrect4, 4 AS AnswerID UNION ALL SELECT q.Answer5, q.IsCorrect5, 5 AS AnswerID ) d (Answer, IsCorrect, AnswerID) WHERE d.Answer IS NOT NULL;
SELECT t.ID AS UserUniqueID, t.UserID, d.TQ AS QuestionID, d.TA AS Answer INTO #TestResults FROM dbo.Tests t CROSS APPLY ( SELECT t.TQ1, t.TA1 UNION ALL SELECT t.TQ2, t.TA2 UNION ALL SELECT t.TQ3, t.TA3 UNION ALL SELECT t.TQ4, t.TA4 UNION ALL SELECT t.TQ5, t.TA5 ) d (TQ, TA);
SELECT * FROM #TestQuestionsAndAnswers; SELECT * FROM #TestResults; GO
SELECT * FROM #TestQuestionsAndAnswers qa JOIN #TestResults tr ON qa.QuestionID = tr.QuestionID AND qa.AnswerID = tr.Answer ORDER BY tr.UserID, qa.QuestionID;
edit: code formatting
I still prefer the CROSS APPLY VALUES approach to UNPIVOT (see the first link in my signature). 
That is, if you were working in SQL 2008 of course.
No loops! No CURSORs! No RBAR! Hoo-uh!
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
Need to UNPIVOT? Why not CROSS APPLY VALUES instead? Since random numbers are too important to be left to chance, let's generate some! Are you too recursively challenged? Splitting strings based on patterns can be fast!
|
|
|
|
|
SSCertifiable
       
Group: General Forum Members
Last Login: Today @ 8:35 PM
Points: 6,694,
Visits: 11,709
|
|
dwain.c (1/16/2013)
opc.three (1/12/2013)
Not a problem. I hadn't played with unpivoting data in a long time so I took it on as a learning challenge. It took me about a half hour to produce the code. Here, however, is a much improved version that does not use UNPIVOT at all that should be easier to understand, and more importantly should scale up much better performance-wise. IF OBJECT_ID(N'tempdb..#TestQuestionsAndAnswers') IS NOT NULL DROP TABLE #TestQuestionsAndAnswers;
IF OBJECT_ID(N'tempdb..#TestResults') IS NOT NULL DROP TABLE #TestResults;
SELECT q.Id AS QuestionID, q.Question, d.Answer, d.IsCorrect, d.AnswerID INTO #TestQuestionsAndAnswers FROM dbo.QuestionList q CROSS APPLY ( SELECT q.Answer1, q.IsCorrect1, 1 AS AnswerID UNION ALL SELECT q.Answer2, q.IsCorrect2, 2 AS AnswerID UNION ALL SELECT q.Answer3, q.IsCorrect3, 3 AS AnswerID UNION ALL SELECT q.Answer4, q.IsCorrect4, 4 AS AnswerID UNION ALL SELECT q.Answer5, q.IsCorrect5, 5 AS AnswerID ) d (Answer, IsCorrect, AnswerID) WHERE d.Answer IS NOT NULL;
SELECT t.ID AS UserUniqueID, t.UserID, d.TQ AS QuestionID, d.TA AS Answer INTO #TestResults FROM dbo.Tests t CROSS APPLY ( SELECT t.TQ1, t.TA1 UNION ALL SELECT t.TQ2, t.TA2 UNION ALL SELECT t.TQ3, t.TA3 UNION ALL SELECT t.TQ4, t.TA4 UNION ALL SELECT t.TQ5, t.TA5 ) d (TQ, TA);
SELECT * FROM #TestQuestionsAndAnswers; SELECT * FROM #TestResults; GO
SELECT * FROM #TestQuestionsAndAnswers qa JOIN #TestResults tr ON qa.QuestionID = tr.QuestionID AND qa.AnswerID = tr.Answer ORDER BY tr.UserID, qa.QuestionID;
edit: code formatting I still prefer the CROSS APPLY VALUES approach to UNPIVOT (see the first link in my signature).  That is, if you were working in SQL 2008 of course. Agreed. Very nice article. The graphics are excellent towards visualizing what unpivoting really means in terms of reshaping the data.
I think my second code-effort on this post is equivalent to the CROSS APPLY VALUES approach you showed except that the technique is also usable on SQL Server 2005. I will also say that a row constructor reads a little cleaner than a UNION ALL.
__________________________________________________________________________________________________ There are no special teachers of virtue, because virtue is taught by the whole community. --Plato
Believe you can and you're halfway there. --Theodore Roosevelt
Everything Should Be Made as Simple as Possible, But Not Simpler --Albert Einstein
The significant problems we face cannot be solved at the same level of thinking we were at when we created them. --Albert Einstein
1 apple is not exactly 1/8 of 8 apples. Because there are no absolutely identical apples. --Giordy
|
|
|
|