I think you've pretty much nailed it on your initial schema.
However, since we're dealing with an MCQ scenario, you don't require an "Answers" table - the answer can be included in the question (along with the two incorrect answers - see below). This will greatly simplify matters.
Another smaller change that I would recommend is having a Question_ID field as the PRIMARY KEY
in the Question table.
I've prepared a schema below - it's MySQL I'm afraid, I don't use Microsoft SQL Server very often and don't have an instance to hand. It shouldn't be too hard to "translate".
A few comments.
Instead of using just "ID" as a field name in every table, I recommend that you use "Table_Name_ID" - it makes your SQL clearer and also helps with debugging - if you receive a message saying something like "... error with ID on insert..." - you don't know to which table's ID is the message referring, whereas if you name them explicitly, the error message becomes meaningful.
CREATE TABLE Student (Student_ID int, Name VARCHAR(25));
CREATE TABLE Question (Question_ID int, Name VARCHAR(25), Question_Text
VARCHAR(64000), Answer1 VARCHAR(4096),
Answer2 VARCHAR(4096), Answer3 VARCHAR(4096),
Correct_Answer TINYINT);
CREATE TABLE Student_Response (Student_ID int, Question_ID int,
Student_Answer TINYINT);
If you have the questions formulated such that they are marked 'A', 'B' or 'C', you will need to modify TINYINT to CHAR(1).
You'll notice that I use relatively long and (hopefully) easy to understand names for my FOREIGN KEY
s &c. There are two reasons for this:
Programmers don't have to go digging through documentation to find out what an entity is - it is self-explanatory,
Absolutely essential for debugging - which is where the vast majority of applications spend most of their time. Getting a message that "... constraint SYS00003433 has been violated..." isn't exactly helpful. Oracle is great for giving unnamed constraints its own "special" system generated names.
You'll also notice that I use singular table names. I recommend that you do the same - that way you never have to think about "Hmmm... is it student or students?" Either way, pick a standard and stick to it.
If you Google "database design best practices", you'll get any number of sites - take the time and trouble to read a few of them and see what the consensus is - if lots of people think it's a good idea, it probably is!
ALTER TABLE Student_Response
ADD CONSTRAINT fk_sr_student FOREIGN KEY (Student_ID)
REFERENCES Student (Student_ID);
ALTER TABLE Student_Response
ADD CONSTRAINT fk_sr_question FOREIGN KEY (Question_ID)
REFERENCES Question (Question_ID);
This unique constraint is to eliminate the possibility of two answers to the same question.
ALTER TABLE Student_Response
ADD CONSTRAINT uq_sr_student_question
UNIQUE (Student_ID, Question_ID);
Even though you specifically rule it out, it should be relatively easy to add an exam (same exam, different times) table or possibly an "attempt" table for that and then have an exam table for different exams - i.e. databases101, databases201.
Maybe you should consider a date or even a datetime field associated with attempt - take the same exam in the morning and afternoon?
At the end of the day, one could design till the cows come home. Avoid compulsive designing disorder - by that I mean choose (in advance) a point at which you'll be satisfied with the functionality of your system and stop there. I know how easy it is to fall into the trap of continually adding "bits and bobs" and getting no real work done.