Need help on database designing - mysql

I am currently out of idea how to design this table so I would really like some suggestions. Description as follows:
Table will hold 3 exam result.
Exam A: 8 mandatory subject with infinite optional subject.
Exam B: 6 mandatory subject with infinite optional subject.
Exam C: 1 mandatory subject with 4 optional subject.
Feature to keep in mind:
Each subject's result need to be searchable (eg: Find A for Math in Exam A)
Basic total calculation (eg: calculate how many As in Math for Exam A)
Just inserting data I would be able to think of something however when putting the features into the mix, it just won't work.
My last resort is having a single table with: studentid, exam, subjectcode, result. This will work as in searchable and calculable however I have a feeling of a very messy and huge database in the long run.
My current design (given by my friend):
Each subject and its result have its own field. It works but very hard to expand (add more subjects).
Any recommendations?

Possible table structure (leaving out column definitions):
Exam
---------
Exam_ID
Exam_name
number_of_req_subjects
number_of_opt_subjects <---- -1 could be infinite
Subject
-----------
Subject_id
subject_name
exam_subject
------------
exam_subject_id
exam_id
subject_id
required
exam_result
------------
exam_result_id
exam_subject_id
result
To get the number of A's for Math in Exam A:
SELECT count(exam_result_id)
FROM exam_result er, exam_subject es, subject s, exam e
WHERE er.exam_subject_id = es.exam_subject_id
AND es.subject_id = s.subject_id
AND es.exam_id = e.exam_id
AND e.exam_name = 'A'
AND s.subject_name = 'MATH'
(I know using joins would be better than where to join the different tables, but I'm being a bit lazy).
The subjects result being searchable...we don't have enough information. In fact, my answer may be completely off, but is as close as I think I can get it with the given information at the moment. Making something searchable is just a matter of creating a sufficiently useful select statment.

Related

MySQL Query to get student grades AND class average

I am fairly new to the world of SQL and am finding the syntax a tad bit awkward to work with while I try to understand how joins and such work. I am practicing by building a small web app that lets you pick a date and possibly a name of a student (if none is defined then all students are shown). My idea is that basically multiple tables (one per student) will be generated off of a given query and it would show the student's name and other related info, along with this it also will show the average grade of all the students along side that specific students information. However, I am not sure how to actually make a query that will return all the students, those with and without grades on a given date, alongside the overall average of that test/quiz on said date.
The tables I am working with are student which has a student_id, name and sex. An Event table that has an event_id, type (test or quiz) and a date. And finally a score table that has an event_id, student_id and a score.
Essentially the resulting query would return a table with these columns.
| student_id | Name | Date | Type | Grade | Class Avg |
every row is a unique student, the date the given test or quiz was taken on, the grade they got (if they took test/quiz, otherwise it's NULL) and then the class avg for that test/quiz. I know how to get everything up to the class average. I'm not even sure if it is or isn't possible without doing 2 queries or to calculate it myself while rendering the webpage.

Database Design for Time Table Generation

I am doing a project using J2EE(servlet) for Time Table Generation of College.
There are Six Slots(6 Hours) in a Day
4 x 1 HR Lectures
1 x 2 HR Lab
There Are three batches ( 3IT, 5IT, 7IT)
2 Classroom
1 LAB
Each slot in the time table will have
(Subject,Faculty)
For Lab I will duplicate the slot.
The Tables
Subject(SubjectID INT, SubjectName VARCHAR);
Faculty(FacultyID INT,FacultyName VARCHAR,NumOfSub INT,Subjects XYZ);
Here I am not able to decide the DATATYPE for subject. What should I do ? Since a faculty can teach multiple subjects ? Also how to link with Subject Table ?
P.S. Using MySQL Database
You don't want to actually store either NumOfSub (number of subjects) OR Subjects in Faculty. Storing subjects that way is a violation of First Normal Form, and dealing with it would cause major headaches.
Instead, what you want is another table:
FacultySubject
----------------
FacultyId -- fk for Faculty.FacultyId
SubjectId -- fk for Subject.SubjectId
From this, you can easily get the count of subjects, or a set of rows listing the subjects (I believe MySQL also has functions to return a list of values, but I have no experience with those):
This query will retrieve the count of Subjects taught by a particular teacher:
SELECT Faculty.FacultyId, COUNT(*)
FROM Faculty
JOIN FacultySubject
ON FacultySubject.FacultyId = FacultyId.FacultyId
WHERE Faculty.FacultyName = 'Really Cool Professor'
GROUP BY Faculty.FacultyId
... and this query will get all the subjects (named) that they teach:
SELECT Subject.SubjectId, Subject.SubjectName
FROM Faculty
JOIN FacultySubject
ON FacultySubject.FacultyId = FacultyId.FacultyId
JOIN Subject
ON Subject.SubjectId = FacultySubject.SubjectId
WHERE Faculty.FacultyName = 'Really Cool Professor'
(note that this last returns the subjects as a set of rows ie:
SubjectId SubjectName
=========================
1 Tree Houses
2 Annoying Younger Sisters
3 Swimming Holes
4 Fishing
)

ORDER BY proirity with specific value

I have a table with a column named role and values are as follow:
Scientific staff
PostDocs
Supporting staff
PNUT
Visiting researchers
Secretary
Ph.D. students
Students
Other
I want to use ORDER BY in such a way that Scientific staff comes first. At the moment when I do a query like this, the fields which are Ph.D. students will be returned first (Well because at the moment no row in database has a field with Other in it). Is there a way to achive this using mysql only or should I modify the returned values manually? If so, can you please tell me how?
SELECT * FROM members ORDER BY role
You can do it without an additional table and join, just do:
SELECT * FROM members
ORDER BY
CASE role
WHEN 'Scientific staff' THEN 1
WHEN 'PostDocs' THEN 2
WHEN 'Supporting staff' THEN 5
WHEN 'PNUT' THEN 6
WHEN 'Visiting researchers' THEN 4
WHEN 'Secretary' THEN 3
WHEN 'Ph.D. students' THEN 8
WHEN 'Students' THEN 7
WHEN 'Other' THEN 9
ELSE 10
END
As it is currently implemented, you cannot order by in such a way that Scientific Staff is first, because doing an Oder By sorts it in order of the item in question (in your case, alphabetically it appears by role).
Now, the easy solution to this is to build out a sort priority table with those values in it, assign a numeric priority, then sort by the priority. Let me explain that a little better because it can be confusing:
You make a second table, listing each of these roles, and in a second column give those roles a priority that they will be displayed by.
TABLE:
Role | Priority
Scientific Staff | 1
Ph.D Students | 2
Other | 3
(etc)
You can then do something like this (pseudo-MySQL):
select members.role from members
inner join priority
on members.role = priority.role
order by priority.priority
that will give you the role field from the members table, ordered by the priority you set on the priority table. Since it is an inner join, anyone without a role will not display.

How to perform this MySQL query given this relation diagram

I have the following relation diagram where arrows represent Foreign Keys. The word in the blue is the table name and the words below are column names.
My question is how I could extract the following data from this table:
-what is the GPA of the student with ID=1?
-what are the average GPAs for students by department?
Given that: there are only
five letter grades with values A=4, B=3, C=2, D=1, and F=0, and GPA is the sum of
course credits x course grade value divided by total credits x 4. (so takes.grade is an int from 0-4 inclusive).
I have been trying to figure this out for hours with no avail. Could anyone steer me in the right direction?
Thanks for any help.
Ok, I've actually had to do this for a client over 15 yrs ago, and did for the entire database of all students, not as difficult once you have the pieces.
Without your exact queries as you want guidance.
Start with a single query that pulls data into a TEMPORARY table
CREATE TEMPORARY TABLE AllStudentsCourses
SELECT blah... from blah... join blah.. where... order by ...
A list of all classes a person has signed up for, and while you are at it, have columns computed at the PER-CLASS BASIS the grade earned A-F. You'll also need the credit hours of the class too as that is basis of computing a GPA.
a 3 hour course with an A gets 3 cr hrs towards GPA.
a 6 hour course with an A gets 6 cr hrs towards GPA.
a 6 hour course with a B gets LESS weighted value towards GPA
and you'll need to roll aggregates up.
Now, once you have all the classes a student attempted, you'll need to compute the per-class as sample described. If you want to apply that in the first query, do so.
Once you have that, then, you can roll-up the total credit hrs attempted vs credit hrs earned.
Basic math should help you along.
I didn't quite understand how the GPA is calculated, think there is something wrong with your original post. Here's a starting point that may or may not be right:
SELECT avg(t.grade)
FROM takes t
INNER JOIN course c
ON t.course_id = c.course_id
WHERE t.ID = 1;
SELECT c.dept_name, avg(grade)
FROM takes t
INNER JOIN course c
ON t.course_id = c.course_id
GROUP BY c.dept_name

Count a specific value from multiple columns and group by values in another column... in mysql

Hey. I have 160 columns that are filled with data when a user fills a report form out and submit it. A few of these sets of columns contain similar data, but there needs to be multiple instance of this data per record set as it may be different per instance in the report.
For example, an employee opens a case by a certain type at one point in the day, then at another point in the day they open another case of a different type. I want to create totals per user based on the values in these columns. There is one column set that I want to target right now, case type. I would like to be able to see all instances of the value "TSTO" in columns CT1, CT2, CT3... through CT20. Then have that sorted by the employee ID number, which is just one column in the table.
Any ideas? I am struggling with this one.
So far I have SELECT CT1, CT2, CT3, CT4, CT5, CT6, CT7, CT8, CT9, CT10, CT11, CT12, CT13, CT14, CT15, CT16, CT17, CT18, CT19, CT20 FROM REPORTS GROUP BY OFFICER
This will display the values of all the case type entries in a record set but I need to count them, I tried to use,
SELECT CT1, CT2, CT3, CT4, CT5, CT6, CT7, CT8, CT9, CT10, CT11, CT12, CT13, CT14, CT15, CT16, CT17, CT18, CT19, CT20 FROM REPORTS COUNT(TSTO) GROUP BY OFFICER
but it just spits an error. I am fairly new to mysql databasing and php, I feel I have a good grasp but query'ing the database and the syntax involved is a tad bit confused and/or overwhelming right now. Just gotta learn the language. I will keep looking and I have found some similar things on here but I don't understand what I am looking at (completely) and I would like to shy away from using code that "works" but I don't understand fully.
Thank you very much :)
Edit -
So this database is an activity report server for the days work for the employees. The person will often open cases during the day. These cases vary in type, and their different types are designated by a four letter convention. So your different case types could be TSTO, DOME, ASBA, etc etc. So the user will fill out their form throughout the day then submit it down to the database. That's all fine :) Now I am trying to build a page which will query the database by user request for statistics of a user's activities. So right now I am trying to generate statistics. Specifically, I want to be able to generate the statistic of, and in human terms, "HOW MANY OCCURENCES OF "USER INPUTTED CASE TYPE" ARE THERE FOR EMPLOYEEIDXXX"
So when a user submits a form they will type in this four letter case type up to 20 times in one form, there is 20 fields for this case type entry, thus there is 20 columns. So these 20 columns for case type will be in one record set, one record set is generated per report. Another column that is generated is the employeeid column, which basically identifies who generated the record set through their form.
So I would like to be able to query all 20 columns of case type, across all record sets, for a defined type of case (TSTO, DOME, ASBA, etc etc) and then group that to corresponding user(s).
So the output would look something like,
316 TSTO's for employeeid108
I hope this helps to clear it up a bit. Again I am fairly fresh to all of this so I am not the best with the vernacular and best practices etc etc...
Thanks so much :)
Edit 2 -
So to further elaborate on what I have going on, I have an HTML form that has 164 fields. Each of these fields ultimately puts a value into a column in a single record set in my DB, each submission. I couldn't post images or more than two URLs so I will try to explain it the best I can without screenshots.
So what happens is this information gets in the DB. Then there is the query'ing. I have a search page which uses an HTML form to select the type of information to be searched for. It then displays a synopsis of each report that matches the query. The user than enters the REPORT ID # for the report they want to view in full into another small form (an input field with a submit button) which brings them to a page with the full report displayed when they click submit.
So right now I am trying to do totals and realizing my DB will be needing some work and tweaking to make it easier to create querys for it for different information needed. I've gleaned some good information so far and will continue to try and provide concise information about my setup as best I can.
Thanks.
Edit 3 -
Maybe you can go to my photobucket and check them out, should let me do one link, there is five screenshots, you can kind of see better what I have happening there.
http://s1082.photobucket.com/albums/j376/hughessa
:)
The query you are looking for would be very long and complicated for your current db schema.
Every table like (some_id, column1, column2, column3, column4... ) where columns store the same type of data can be also represented by a table (some_id, column_number, column_value ) where instead of 1 row with values for 20 columns you have 20 rows.
So your table should rather look like:
officer ct_number ct_value
1 CT1 TSTO
1 CT2 DOME
1 CT3 TSTO
1 CT4 ASBA
(...)
2 CT1 DOME
2 CT2 TSTO
For a table like this if you wanted to find how many occurences of different ct_values are there for officer 1 you would use a simple query:
SELECT officer, ct_value, count(ct_value) AS ct_count
FROM reports WHERE officer=1 GROUP BY ct_value
giving results
officer ct_value ct_count
1 TSTO 2
1 DOME 1
1 ASBA 1
If you wanted to find out how many TSTO's are there for different officers you would use:
SELECT officer, ct_value, count( officer ) as ct_count FROM reports
WHERE ct_value='TSTO' GROUP BY officer
giving results
officer ct_value ct_count
1 TSTO 2
2 TSTO 1
Also any type of query for your old schema can be easily converted to new schema.
However if you need store additional information about every particular report I suggest having two tables:
Submissions
submission_id report_id ct_number ct_value
primary key
auto-increment
------------------------------------------------
1 1 CT1 TSTO
2 1 CT2 DOME
3 1 CT3 TSTO
4 1 CT4 ASBA
5 2 CT1 DOME
6 2 CT2 TSTO
with report_id pointing to a record in another table with as many columns as you need for additional data:
Reports
report_id officer date some_other_data
primary key
auto-increment
--------------------------------------------------------------------
1 1 2011-04-29 11:28:15 Everything went ok
2 2 2011-04-29 14:01:00 There were troubles
Example:
How many TSTO's are there for different officers:
SELECT r.officer, s.ct_value, count( officer ) as ct_count
FROM submissions s JOIN reports r ON s.report_id = r.report_id
WHERE s.ct_value='TSTO'
GROUP BY r.officer