Type-based database design - mysql

I want to rate (Very Good, Good, Medium, Bad...) 2 objects: Student and Teacher. Which design solution is better?
Solution 1:
Students(StudentID, Rating,...)
-----------------1--------Good-----
-----------------2--------Bad-----
-----------------3-----Very Good-----
Teachers(TeacherID, Rating,...)
-----------------1-----Very Good-----
-----------------2--------Bad-----
-----------------3--------Bad-----
Solution 2:
Students(StudentID, RatingTypeID,...)
-----------------1----------------2----------
-----------------2----------------1----------
-----------------3----------------3----------
Teachers(TeacherID, RatingTypeID,...)
-----------------1----------------1----------
-----------------2----------------1----------
-----------------3----------------3----------
RatingType(RatingID, RatingDescription,...)
-----------------1-------------Very Good---------
-----------------2---------------Good--------------
-----------------3----------------Bad---------------
If both of them are not good enough, can you give me some suggestions? Thanks!

Solution 2 is the best from those two, but if You want to have multiple votes in the course of your application's life, you should have a table where you identify what is the subject of the vote, and another where you store the votes:
Student:
id
name
class
...
Teacher:
id
name
subject
...
voterType
id
description (student or teacher)
contest:
id
description (ex: 1st Semester 2013)
contestVotes:
id
contestId
voterType (Teacher or Student)
voterId
ratingTypeId

Between the two suggested solutions, I would definitely choose the second one, for the following reasons:
Storing a Rating as a number can come handy in cases where ordering or aggregates are involved, in which cases a string is pretty much useless.
Making the Rating column a Foreign Key to the RatingType.RatingID enforces a constraint, that a Rating can only have values from a very specific set, with very specific meaning. Plus, you could potentially add extra columns to the RatingType table in the future, adding value to your ratings.
As for an improvement suggestion, since you asked, consider implementing this using IS-A relations. A teacher, as well as a student, are apparently both Persons and have common attributes to an extent. I would create a Person superclass table containing the common attributes (i.e. first name, last name, address, phone etc) and then make the primary keys of students and teachers also foreign keys to Persons.
Notice that, a rating is a common attribute too. So it's only natural to appear in the Persons table. Unless of course there are different types of ratings for teachers and students, in which case you would have to implement two different RatingType tables.

Related

Is it antipattern to create a junction table with more than two foreign keys?

I am designing a database for school management.
Here instead of a single school, there are multiple schools with their own students, classes, teachers and subjects.
Here is the requirements.
• A school can have many classes
• A class can have many sub classes
• Many Students can belong to a section of a class
• Many Teacher can belong to a section of a class
• Many Subjects can belongs to a section of a class
• School wants to manage classes
• School wants to manage sections
• School wants to manage subjects in a section of a class
• School wants to assign a teacher for a subject in a section of a class
• School can assign a student a section of a class
Also, some school can have classes as named One, Two, Three and Some may have First, Second and Third. Also same for sections or sub classes
For entities School and Teacher things are straight forward. Below is my approach for them.
School
--------------
id
name
...
Teacher
--------------
id
school_id
name
But I am facing problem while mapping classes and sections for a school.
I tried to make two other entities classes and sections and give them a foreign key of the school
SchoolClass
-----------------
school_id
class_name
...
SchoolSection
----------------
school_id
section_name
...
For mapping a school's class to all its section I created a junction table, as it will be many to many relationship.
SchoolClassSection
---------------------------------------------------------
school_class_id
school_section_id
But as I mentioned above I also need to add subjects and teachers to a section of the class so tried something like below.
SchoolClassSections
---------------------------------------------------------
school_class_id
school_section_id
subject_id
teacher_id
But now I ended up having four foreign keys in the junction table.
Is there no issues in having more than two foreign keys in a junciton table?
Also, I need to add students too, but I can't now figure it out How to move further for students relation for classes, sections?
One thing I could thing of like below
student
-----------
school_id
school_class_section_id // but if SchoolClassSections can have subject_id and teacher_id too it will become confusing
No, it is not an "antipattern". There are many examples where a junction table might have more than two foreign keys:
A doctor's appointment might have a doctor, a patient, and a clinic.
A retail order might have a customer, a location, and a payment type.
An online subscription might have a customer id, product, payment type, and source.
Those are just some examples from other domains (and they do not even include a date dimension). It is not uncommon for a table to have multiple foreign keys.
I didn't analyze your schema, due to time constaints here.
But there's no problem from either the relational point of view or the SQL point of view with a table or junction table having more than two foreign keys. In fact, that's pretty common.
Some concepts, especially OO concepts, do not fit well with SQL.
SQL has "only":
1:1 relationships (generally this should not be used)
1:many (implement via a link in one table to the other)
many:many (requires a separate 'junction' table)
In each case "1" can degenerate to "0" and "many" can degenerate to "1" or "0". Usually "0" is not represented explicitly but by the absence of rows.
To create schemas:
Think of what "entity" tables to have. (Student, Class, School, etc.)
Create relations, thinking in terms of 1:many and many:many.
Optionally, establish FOREIGN KEYs for the links. (For referential integrity; implicitly creates an INDEX)
Make sure the appropriate columns are INDEXed. (For performance)
Later...
Write the SELECTs, UPDATEs, etc.
Use those queries to decide whether other indexes are needed.
Your question is mainly about the many:many tables.
The basic many:many table has exactly 2 column (links to two other tables)
The basic has two composite indexes (PRIMARY KEY(a,b) and INDEX(b,a))
Sure, make it many:many:many (Not common, but reasonable)
Add columns for attributes about the relations (also not common, but OK)
Add composite indexes for the queries that depend on those attributes (for performance)
More discussion of many:many: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table

Creating a table for each student. Is it considered a bad practice?

i have hit a road bump where i need to list all the current courses for students and instructors and i have 2 tables one of them is called students and the second one is called courses. I was thinking of creating a field for students called courses and then separating entries with a comma so i can use the WHERE IN clause but creating a table for each student is much easier.
As you have a many-to-many mapping, consider using a linking table with student_id and course_id columns.
I was thinking of creating a field for students called courses and then separating entries with a comma
Bad idea, and you're certainly not the first to have it.
creating a table for each student is much easier
Worse idea, and you're certainly not the first to have it.
Don't create database structures that require you to parse information from disorganized blobs. And definitely don't create database structures that require you to change the structure every time data changes.
What you're describing, the relationship between Student and Course, is called a many-to-many relationship. To achieve it, all you need is a "linking table" between the two entities. Consider something like this:
Student
----------
ID (PK)
Name
Course
----------
ID (PK)
Name
Simple enough representation of those two entities. Now all you need is a third table to connect them in a many-to-many relationship:
StudentCourse
----------
ID (PK)
StudentID (FK)
CourseID (FK)
A few things to note:
The name of the table doesn't have to follow this convention, this is just a common practice. You can call it anything you like. Enrollment might be a good name for this as it grows into its own entity.
This doesn't need its own ID (PK), its primary key could be a composite of the two foreign keys (since each pair thereof should also be unique in this domain).
This can quickly grow into its own entity if it has more data than just the relationship. For example, if there is specific information about a student's enrollment in a course which is specific to the combination of the two, but not specific to either entity itself. A registration number of some kind, a date/time of enrollment, etc. This table would become its own entity alongside the other two and be more than just a structural linking table.

Designing MySQL database

I have three tables,
student, studentclass , class
student have sid as primary key, class have cid as primary key.
studentclass ties student and class together and has two columns, sid,cid (no special keys).
Is it possible to get rid of studentclass table and use student and class tables only, without creating duplicate entries in student or in class tables?
(class can have multiple students and student can attend multiple classes)
Thanks.
If the business logic states that, one student can attend multiple classes then it is good to have a linking table, StudentClass.
You can think of this as a Many to Many relationship where one student can attend multiple classes and one class can have multiple students.
The studentclass table is required assuming that students attend more than one class.
If they do not you can simply add a classId field into the students table and get rid of the studentclass table.
Without the explicit columns, and having previously written a college registration system many moons ago, here are some of the tables that I had implemented.
Student - obvious, list of students, primary information, etc
ClassCategory - Generic categories... (ENG)English, (MTH)Math, (SCI)Science, etc, not the specific class level, but the categories
ClassCourse - These are the things that would be found in a syllabus.. ENG-101, MTH-210, etc. This would have the common information describing what the class was about, not who was teaching, credit hours, etc but the material covered, maybe any pre-requisites, basic syllabus for someone to review content.
Semester - List of semesters, such as Winter-2013, Spring-2014, etc.
Facility - List of facility locations that a given class would be taught -- could be buildings, campus, etc
Teacher - list of teachers, there contact information, whatever, regardless of specific classes they might teach.
ClassOffering - Here is where all the courses would be, when offered, etc and would have its own PK ID, but also the ClassCourse, Semester offered, Facility, teacher and specific room and times. You could have the same "ENG-101" course offered 5 times in a day for day and evening classes by different teachers and time slots.
StudentClasses - This is what you are currently at. This would have which student and which specific class OFFERING they enrolled in. Additionally, at this record you could have a drop, withdrawn status, etc and what other settings may be specific, such as credits attempted, earned, final grade, date completion, etc... This table would be the basis of computing GPA for a student.
EACH of these tables would have their own respective "PKID" values and each table SHOULD have their own.
Although this is not an obvious complete database, but it hopefully can lead you to a better consideration of what you may need to consider.

Adding external IDs to primary key field

I am creating a database for a university dept(for internal use) and this database tracks issues related to people. I get information of only employees at the university and I am tracking them using their university ID. But the database is also intended for people who are not employees at the university or even sometimes people outside the university. I want to assign an ID to these people but store values within same column as university id. Any ideas how I should tackle this issue? I don't know how to keep the univ id and the no. I am going to give to the others in the same column and yet treat them differently (when needed). How do people usually tackle such issues?
PS: I do not like auto numbers since I cannot delete an ID and get it back into the database
Your best bet here is probably to create a common Person table for all people which simply tracks an Id, then relate separate tables for each of the different kinds of people (ex. Employee, Student, etc.) to it - note that all of these names are just examples. Each of these tables would contain a foreign key to the Person table. In effect, this logically make each of them a different "subclass" of person.
For example, Employee my be related to Person via the foreign key
[Person.PersonId] {PK} <==(1-0)==> {FK:Person.PersonId} Employee.PersonId
This is generic for any Other entity:
[Person.PersonId] {PK} <==(1-0)==> {FK:Person.PersonId} Other.PersonId
Note that any columns common to all types of person may exist directly on the Person table, with each of the "subclasses" of person only recording columns specific to its particular type.
In addition, you may create a view with joins these tables to present a "combined" generic record for people. In some cases, it's useful to include a column in the view that simply indicates which table an individual record came from (ex, class or type.
I personally would not want to mix the two different kind of ids within one field. This is just waiting for trouble when you migrate since you need to keep these apart by convention or through other fields.
You will of course use the uni id to search the person ...
(uni id and an id for people not on uni)
Approach 1 - introduce an additional table
Issue
- id
- person_id
Person
- id
- university_person_id (optional)
University Person (table)
- id
Approach 2 - make the university ref id optional
Issue
- person_id
Person
- id
- university_ref (optional)
What do you think?
But if you really want to go along with mixing the two kind of ids within one field I suggest to use a prefix followed by a generated number.
EXTERNAL-123456
You can also introduce an additional field external_contact (boolean) or contact_type 'Uni' or 'External'. Also add a unique index on the two combined.
Hope this will give you some food for thought :)

Relational Table Normalization

I would like to know if the relational table in BCNF
Student(StudentNum, NRIC, DateOfBirth, BookTitle)
• Student’s number (StudentNum) uniquely identifies the National Registration Identity Card (NRIC) and the date of birth of the student (DateOfBirth).
• The NRIC determines the student’s date of birth (DateOfBirth).
According to my analysis, the relation is in 2NF. And after changing to BCNF it looks like this
Student(StudentNum, NRIC, BookTitle)
StudentDetails(NRIC, DateOfBirth)
My query;
Before the change 2NF
After the change BCNF
Am i correct.
The idea behind normalization is to eliminate redundancy of rows as much as possible by putting creating additional tables for those columns that may seem to inflict any redundancy on the table.
For example if we start with the following table: Student(StudentNum, NRIC, DateOfBirth, BookTitle) The unique columns in this case are the StudentNum and NRIC, the other 2 fields are not because other students may have the same date of birth and others may have borrowed the book of the same title. From there we see the need to normalize in order for us not to fall into the redundancy of data, for example what if the same student borrowed 100 different books?
If everything is in a single table, we may end up with lots of redundant(repetitive) data.
I suggest you check out this guide to the 5 normal forms http://www.bkent.net/Doc/simple5.htm
Update:
I think the beginning relation better to be considered 1st normal form given that everything is within a single table. Your resulting relation is 2NF I guess because what if different students have borrowed the same book? That may lead to repetition in the Student table.
I think you have to give more info regarding the scenario constituting your relations so we can analyze this better. It highly depends on the business rules.
No. Student is in 1NF, not 2NF.
You're starting with
Student(StudentNum, NRIC, DateOfBirth, BookTitle)
and these dependencies.
StudentNum->NRIC
StudentNum->DateOfBirth
NRIC->DateOfBirth
A relation is in 2NF if and only if
it's in 1NF, and
every non-prime attribute is dependent on the whole of every candidate key, not just on part of any candidate key.
So your first job is to determine the candidate keys of the Student relation. The Student relation has only one candidate key, and that's {StudentNum, BookTitle}.
Your textbook should have at least one algorithm for determining all the candidate keys of a relation.
Since NRIC is dependent on StudentNum, and StudentNum isn't a candidate key (it's just part of a candidate key), the relation Student is not in 2NF. Fix that by changing
Student(StudentNum, NRIC, DateOfBirth, BookTitle)
to this, by eliminating the partial key dependency on StudentNum.1
Student (StudentNum, NRIC, DateOfBirth)
StudentBooks (StudentNum, BookTitle)
StudentBooks has no non-prime attributes at all; it's now in 6NF. Student is in 2NF, but not yet in 3NF or BCNF. Do you know why?
It seems you did know why. There is indeed a transitive dependency: StudentNum->NRIC, and
NRIC->DateOfBirth. Fix the transitive dependency like this.
Student (StudentNum, NRIC)
NRIC (NRIC, DateOfBirth)
StudentBooks (StudentNum, BookTitle)
All three of those relations are in 6NF.
This decomposition might look a little odd. That's because textbook examples usually don't use meaningful names for either relations or attributes. Relations are usually named R{ABCD}, R1{ABC}, R2{AD}, etc. The decomposition above involved
projecting a new relation {StudentNum, NRIC, DateOfBirth} to eliminate the partial key dependency,
observing that the name "Student" no longer identified the relation consisting of {StudentNum, BookTitle},
moving the name "Student" from the original relation to the new, projected relation, and
coming up with a new name, StudentBooks, for the original relation.