I'm trying to come up with a database design for the following scenario.
Student can register to a Programme, at a given time student can have
only one registered programme.However, he/she must be able to change
the registered programme at any given time (including registering to a new programme). Ultimately, student can be
registered to multiple programme but he must have only 1 active
programme.
I think it should be a 1-M relationship but how to handle this "1 active programme at a given time" situation?
Your student table will have the ProgramID in relation to the Program table for example that he/she chooses and would be the current program. Now, every time he/she change his/her program that ProgramID will change however there will be a ProgramHistory to record the changes.
So possible table would be Student, Program, ProgramHistory.
Example:
Student
StudentID Lastname Firstname Gender ProgramID
------------------------------------------------------
101 Smith Jason M 1
102 Jones Kate F 2
Program
ProgramID ProgramName
------------------------------
1 Computer Science
2 Nursing
3 Electrical Engineering
ProgramHistory
ID ProgramID StudentID Semester Year
-----------------------------------------------------
1 3 101 Spring 2014
2 2 102 Fall 2014
3 1 101 Fall 2014
To allow for tracking of the history of program enrollment, you need to have a ProgramHistory table that is the intersection of a many-to-many relationship between Student and Program
There are a couple of ways to ensure that there is only one active program at one time for a given student.
One way would be to put an active_program_key column in your student table and make it a foreign key to the Program table. This is probably not the best alternative, since it requires denormalizing data and the resulting duplication might result in data inconsistencies unless you take significant steps to avoid them.
Another option using declarative constraints is to create a unique index on the ProgramHistory table that includes the student_key and the enrollment_date. This ensures that a student can only enroll in once per given date. The active program will be the record with the latest date for any given student.
This second option is simple and avoids duplicating any data. In fairness, the query to retrieve current student enrollments will be slightly more complicated. As always, design is about trade-offs.
Assuming that students can change programs at just about any time (i.e. not just between semesters) then you want to have a program_start_date in your ProgramHistory table.
Related
ninjas, I understand that this probably is a "way too broad" or "wrong portal" type question but SO feels like home, so I will give it a try anyways.
I have a table with employees
Table: employee
id, name
1 - John
2 - Jane
3 - Obama
4 - Donald
...nothing fancy. And then there is competencies table (a classifier of special tasks/responsibilieties)
competencies table:
id, name
1 - Janitor
2 - Sysadmin
3 - Programmer
4 - Pilot
...
Each employee can have multiple competencies (relations table)
table: employee_competency
id, employee_id, competency_id
1 - 1 - 1 - John is a Janitor
2 - 1 - 2 - John is also a Sysadmin (imagine that)
3 - 2 - 3 - Jane is a Programmer
4 - 3 - 3 - Obama is a Programmer
5 - 3 - 4 - ...and a Pilot
6 - 4 - 1 - Donald is a Janitor
The existencial problem of a database architecture or how to handle such cases.
I want to be able to define unlimited count of competencies and these competencies can vary from one customer to another (where the project I am programming will be installed - each project installation can have a different set of competencies)
In the code, I want to be able to select employees with specific competency (for example - list all employees who are Pilots)....
By hard-coding the competency ID when listing employees I loose ability to define competencies freely. I could define custom fields in the employee table like is_janitor, is_sysadmin, is_programmer, is_pilot, etc... but then I loose the ability to define unlimited count of competencies...
Is there a way to solve this rather XY problem with a different DB architecture approach?
The key idea here is that you have to have that list that allows you to pick a competency be data-driven as well. So, when you are on the screen/form/page where you are selecting the competency to list, you drive that selection by the table of competencies in the database, passing the ID of the competency as the Value of the selection back to your query so that you can query the list of employees by competency.
You should never put individual IDs into the system. Now, this gets complicated when you have behavior you want to drive based on the competency. This requires thinking at a higher level of abstraction. For example, lets say you have a form where you want to show another tab to allow the customer to select what planes a pilot is certified on. To drive this, I usually create flags that actually define the driving behaviors (like CAN_SELECT_PLANES) to add to a related table. This table defines the capabilities of the system, not the capabilities of the competency. It is important to maintain that abstraction because customers will want to vary their competency name, and you will find new uses for that feature later on.
To select all programmers from the database, use for example:
SELECT
e.name AS empl_name,
c.name AS comp_name
FROM
employee_competency ec,
competencies c,
employee e
WHERE
c.id=ec.competency_id
AND
e.id=ec.employee_id
AND
c.id=3
I am designing a database, and I would like to know;
Can I answer this question with queries, how much skill employees earned from this trainings?
Is this a good structure to do it?
how much money spent per department
how much skill earned per employee
how much skill earned per department
id session_name Skill impact sugg dept function training_value training no
1 PHP Software 3 Sales 2 100usd 1
2 PHP Software 3 Finance 2 100usd 1
3 PHP communication 2 Sales 2 100usd 1
4 PHP communication 2 Finance 2 100usd 1
5 ASP Software 4 Sales 2 200usd 2
6 ASP Software 4 Finance 2 200usd 2
7 ASP database 1 Sales 2 200usd 2
8 ASP database 1 Finance 2 200usd 2
attended training table
id student_id training_no
1 1 1
1 1 2
student table
id name department
1 John 1
2 Mary 2
department table
id name
1 sales
2 finance
In the end I need to find skills for each student
john
software 7
communication 2
database 1
total spent
john 300 usd
total spent by department
sales 300 usd
Your schema looks OK to me.
You should, however, think about entities and relationships.
Your entities seem to be trainings, people, and departments.
You have a many:many relationship for people:trainings. That's good.
You have a one:many relationship for departments:people. That's also good.
It looks like you want some kind of relationship for trainings:departments. I'm guessing here, but you have a sugg dept column in your trainings table. Is that supposed to have a direct relationship to your departments table?
Do you actually need an extra entity called "attendance" rather than just a many-to-many relationship people:trainings. Do you want to record when a person did a training? Do you want to record how much that particular attendance cost? How about what marks they received if there was a quiz?
In that case, you'll want relationships where each person has zero or more attendances, each attendance has exactly one training, and each training has zero or more attendances.
My point: do the hard work of thinking through your entities and relationships, and the result will be a good design for your tables.
If I may put it another way: What part of the real world are you trying to capture in your data base? What's valuable in the real world that you want your data base to hold? In your application ...
Students are people. They are, umm, inherently valuable and persistent entities.
Trainings represent the labor and cost of creating them and presenting them.
Attendances represent the effort of students.
Departments probably pay the bill for attendances. They certainly represent power centers in your application.
What other items of value exist in this corner of the real world? Teachers? Managers? Venues (classrooms)? Equipment? Customers?
My point is, figure out your entities -- the items of value -- and the relationships between them. Then write your table definitions.
Note: This is not an inventory controlling system. I am just trying to map which medication given to which patient. I am not considering how many medication packets etc. Just a single medication event
I am having a sudden confusion with database relationships, even after working with them for years. Below is my situation.
I have a table called patient where it will hold the information of patients. I have another table called medication where it will hold the medicines prescribed for patients.
I want to find the relationship, so I asked the below questions from me.
Can one patient have many medicine prescribed? - Answer: YES
Can one prescribed medicine have many patients? - Answer: No (ex: you can't give a patient a paracetamol to drink, take it out and give it to someone else)
I need to create the foreign key of patient in medication table. I'm confused, because my answer for 1st question tell me it is one to many relationship while the answer for 2nd says me it is one to one relationship.
What is the exact relation when I am planning to add the foreign key of patient in medication table?
Below is my structure
It somewhat depends on the kind of structure of your tables.
Example 1
Patient:
PatientID Name
--------- ----
1 John
2 Matt
Patient_Medication:
PrescriptionID PatientID Name
-------------- --------- ------------
1 1 Antacid
2 1 Paracetamol
3 2 Asthma inhaler
You are in a one to many relationship. Patient John can have multiple medications in prescription table.
Example 2
Patient:
PatientID Name
--------- ----
1 John
2 Matt
3 Katie
Medication:
MedicationID Name
------------ ----
1 Antacid
2 Paracetamol
3 Asthma inhaler
Patient_Medication:
ID PatientID MedicationID
--- --------- ------------
1 1 (John) 1 (Antacid)
2 1 (John) 2 (Paracetamol)
3 2 (Matt) 3 (Asthma inhaler)
4 3 (Katie) 2 (Paracetamol)
5 3 (Katie) 3 (Asthma inhaler)
This situation is a many-to-many relationship where many patients can have many medications and vice versa. Usually Patient_Medication is called a junction table.
Your second question:
Can one prescribed medicine have many patients? - Answer: No (ex: you can't give a patient a paracetamol to drink, take it out and give it to someone else)
I guess here you have assumed that prescribing a medication and actually consuming that mediation (actual tablet) in real world is the same thing.
The medication table is just a name holder for the medication.
Your answer would have been correct if your table "Medication" would be storing actual instances of medication.
E.g.
Medication
Id Name
1 Paracetomol 25mg Instance 1
2 Paracetomol 25mg Instance 2
3 Paracetomol 25mg Instance 3
Now here, table is actually containing medication instances which can not be consumed by two patients. And here your answer "No" is, I guess, correct.
The other thing is, as you said you are not working on inventory system, and just trying to map medication, you are still attached to real world inventory item which cannot be consumed by two patients.
Here you are mixing inventory item in a system where inventory item is not required.
I think the relationship should actually be many-to-many. A given patient record could point to several different medications, and similarly a given medication record could point to several different patients.
One way to implement this would be to create a third table which maps patients to medications (or medications to patients, if you prefer to think of it that way). This table might look like this:
id | patient_id | medication_id | date
1 | 1 | 1 | 2016-12-19
2 | 1 | 2 | 2016-12-18
3 | 2 | 2 | 2016-12-18
The above data would imply that patient 1 took medications 1 and 2, and medication 2 was also being taken by patient 2. I also added a date, which might be a proxy for a given patient visit.
The medication_id could be a unique identifier for a given pack of medication delievered. In another table, each unique medication would be related to a parent table for that medication.
Update:
Your current schema does not look far off, except that the table you labelled medication is actually a bridge table between patients and their medication dosages. You would need a third table which stores the metadata for each medication. This metadata would be constant for all medication dosages, e.g. type of drug, cost, etc.
Could your confusion be the result of not having defined what the medication table actually represents. It seems to me that your are confusing type of medicine and actual packets.
So what kind of relationship are you trying to model? Are you doing a system that can do inventory of how much medicine you have, or are you doing a patient system that can tell you how many patients are getting a particular medication.
I think your answer to question two is wrong, many patients can be on the same medication. The number of packets you have in stock should be handled in a separate table where you could hold information on things like how many packets you have, what their location is and so on.
So you need at least three tables
patient - holds the patient
medication - holds the types of medication
patient_medication - holds the information on what types of medication the patient is on
you can then add things like another table to hold information on how much of a medication you have and where it's stored if that is relevant to the system.
It's not wrong to say that the association is one-to-many in one direction, and one-to-one in the other direction. When planning a database, I often advise people to write out the associations in both directions:
Each patient can have zero or more medications
Each medication belongs to one and only one patient
This helps to determine the cardinality of the relationship and clarify functional dependencies. When only one direction is specified, it can be difficult to distinguish one-to-many from many-to-many associations.
When talking about the relationship as a whole, we take an "overhead perspective" and ignore the perspective of individual entities, so we would call this example one-to-zero-or-more, or commonly just one-to-many.
Many-to-many relationships look like two one-to-many associations when you view it from the perspective of individual entities on either side.
We have a table attendance_details in MySQL that has attendance details for five courses. This table has millions of records.
table structure is
training_date - date on which training happened
student_id - id of the student
course1 - no of hrs attended
course2 - no of hrs attended
course3 - no of hrs attended
course4 - no of hrs attended
course5 - no of hrs attended
I need to expose the information to another app which will query the attendance details.
and the query pattern is always "did a given student attend course4 all the day between date1 and date2 ?"
if the student attended atleast one hour for that day then it will be considered as attended.
the result could be
attended all the day between date1 and date2
attended between date1 and date2, but absent for some days
not appeared at all between date1 and date2
I need to provide data in simplified way in new table, so that another app can get the details by querying.
my objectives are
reduce no. of records substantially in new table, so that the query would run fast. faster querying is main objective
data model should be easier for querying
constraints :
i do not want to expose attendance_details, just because it is huge and highly transactional.
it is not possible to chanage structure of attendance_details.
Below is what i have tried
table to represent first & last attendance date, first & last absent date
+------------+------------------+-----------------+--------------+------------------------+
| student_id | first_attendance | last_attendance | first_absent | last_absent |
+------------+------------------+-----------------+--------------+------------------------+
| 123 | 2015-01-01 | 2015-01-30 | 2015-01-15 | 2015-01-21 |
+------------+------------------+-----------------+--------------+------------------------+
in above table design the dates become specific to courses. hence i need 4 courses x 4 columns, totally 16 columns. this will increase if i add more courses.
Also attempted to represent each month records as bitmap , but that makes programming logic complex.
I'd say you're close.
Let's go over the relationships.
A student takes 1 or more courses.
A student attends a course all days between 2 dates.
A student attends a course some days between 2 dates.
A student did not attend a course between 2 dates.
So let's look at the object tables first. I'm assuming there's a Student table and a Course table already in the database.
The first table is a junction table of Student and Course.
StudentCourse
-------------
Student ID
Course ID
Course Started Date
Course Ended Date
The primary key is (Student ID, Course ID). This allows us to query on the courses that a student is taking. We also have a unique index on (Course ID, Student ID). This allows us to query on the students attending a course.
Now that we've established the start and end date of the course, we can keep a record of each student's attendance,
We need one more class to complete the relationships, Attendance. Here's what attendance looks like.
Attendance
----------
Student ID
Course ID
Start Date
End Date
Is Present
This table has a primary key of (Student ID, Course ID, Start Date). There's also a unique index on (Course ID, Student ID, Start Date).
The idea here is that for each student, you create enough rows to describe a student's presence or absence on a particular range of dates. If you want to make this easier, remove the End Date from the table, and you'll have a row for each date of the class.
I'm not sure what your example row is telling me, but here's what I mean.
Student ID Course ID Start Date End Date Is Present
123 456 2015-01-01 2015-01-14 true
123 456 2015-01-15 2015-01-21 false
123 456 2015-01-22 2015-01-31 true
Since all of the dates are covered, you can query using the SQL clause WHERE "Start Date" IS BETWEEN date AND date to get the rows you want.
I'm developing a web application about TV shows. And i need help with the database design.
I made a list of what i need, but i can't figure out how to design it. I have the basic tables. Series, episodes, seasons etc. What i can't do is how to relate people with episodes/series. Here is my list:
There should be multiple people type. Actor/director/writer/guest etc.
I don't think creating seperate table for each type is a good idea. So there should be one people table. And i need to store the type somewhere.
A person may be in 1 or many series.
This can be done with people_serie table with foreign keys to people and series tables. But i need a way to relate a person to episodes too.
An actor may play 1 or many roles.
This can be done with person_role table.
This is where its getting complicating.
A role may be in 1 or many episodes in a serie.
A person may belong to more than one type in a serie. Ex: actor AND director
I hope i make it clear what the problem is.
Well, you're correct not to split the People table.
the first thing to do is add a Roles table, that will contain role id and role title (each column should be unique - you don't want 2 different ids for the Actor role...)
TblRoles
RoleId RoleTitle
-------------------
1 Director
2 Writer
3 Actor
Then you add a PersonToSeries table, that will hold it's own id, the person's id and the series's id.
This table will hold every person ever working on that series, being a regular staff member or a 1 episode guest.
TblPersonToSeries
PTSId PersonId SeriesId
---------------------------
1 1 1
2 3 8
3 4 7
The next table you will need is a PersonToEpisode table, that will hold the PersonToSeries id and the episode id, and the role id.
In this table you only need to keep integer ids so it's very light weight, and you will specify for each record in PersonToSeries the episodes it is relevant for.
TblPersonToEpisode
PTEPTSId RoleId
-------------------
1 2
2 3
3 1
When a person is usually the director of a series, but makes a guess appearance in an episode of that series, you can simply add 2 rows in PersonToEpisode for that PersonToEpisode with a different role id. (one for Actor and one for Director)
TblPersonToEpisode
PTEPTSId RoleId
-------------------
13 1
13 2