Database model for a school timetable - database

I am trying to design a DB model for a school timetable, and have some issues figuring out a model that would work with my requirements.
Domain entities:
Subject - something that is taught over the course of a year. eg: English, Programming, etc.
Group - a group of students.
Lesson - a recurring event where students are taught some specific subject. Example:
every Monday at 10:00 group A is taught Programming.
The original requirements were very basic.
CRUD for Subjects.
CRUD for Groups.
Ability to create recurring events that span some period of time. (note: no editing was allowed after creation).
The current model I use is:
Subjects
id:int
name:string
Groups
id:int
name:string
Lessons
id:int
name:string
startDate:date (ex: event starts recurring from Jan 1 2021)
endDate:date (ex: event recurring ends on Dec 31 2021)
startTime:time (ex: 10:00)
endTime:time (ex: 11:00)
dayOfWeek: flag enum that takes values Monday-Sunday
(we have more fields that are responsible for recurrence, but they are ommited as they are not very relevant to my question).
Currently, entire series of events is stored as a single row in a database.
This was working fine, but now additional requirements were added and I am having issues adjusting my model to accommodate them.
New requirements are:
ability to grade students for each lesson
ability to edit lessons (for example shift start/end time 1 hour for event series; change the day on which event occurs etc)
ability to shift a single event in a series (say teacher woke up sick and needs to move lecture from Monday to Tuesday just for this Monday)
#1 in theory is simple - we create a new table Grades that has fields
lessonId:int
userId:int
date:date
grade:int?
but it won't work once we take into account new requirement #2 (ability to edit lessons).
let's say we have an event that occurs each Monday. an event occurred on Monday, Jan 1st. we graded some students, so we have some grades tied to that date.
then we go to edit our lesson to occur on Tuesdays instead of Mondays.
it is no longer possible to map existing grades to this lesson, as the dates no longer match.
#2 editing lessons seems like a pretty straightforward operation..until you consider grades. basically, the only issue with this requirement is the one described in #1
#3 no idea how to implement this, considering it should be compatible with other requirements.
I need help figuring out the database model that would satisfy those requirements.

From your description I take it that the lessons table also has a subject_id and a groups_id, which you merely forgot to put in your table column list.
Let's look at the tasks:
ability to grade students for each lesson
This is not easy. So far you have groups attending lessons. So to start this, you should add a students table to the database. Then, depending on whether a student can belong to more than one group or not, you'd either have the group ID in the student table or create a bridge table group_student.
Now, what does each "lesson" mean in this requirement? So far a lesson is a recurring event (your example: "every Monday at 10:00 group A is taught Programming"). That would mean you'd want a student_lesson table to be able to store the grade. The only problem I see here is that you could store a student_lesson row for a student that doesn't attend the lesson, if you stick to single IDs. Using composite IDs would solve this. The student_lesson table would have student_id, group_id, lesson_id, and grade. And id would have foreign keys on (student_id, group_id) and on (group_id, lesson_id).
If, however, lesson means a single lesson in the recurring lessons, then you need a single_lesson table, too.
ability to edit lessons (for example shift start/end time 1 hour for event series; change the day on which event occurs etc)
Should be no problem. These are just attributes that can be changed, anyway. Maybe you want a history table to see that the Tuesday lesson took place on Mondays until a month ago, but so far there is no requirement for this.
ability to shift a single event in a series (say teacher woke up sick and needs to move lecture from Monday to Tuesday just for this Monday)
Maybe you already have a single_lesson table because of requirement #1. Then each lesson occurrence already gets its one row with a date and sometimes that Monday would become a Tuesday. You could even store both dates, original date/time, new date/time. Maybe even a text for a reason.
If task #1 doesn't require a single_lesson table, because grades are per recurring lesson, then you only need a single_lesson_exception table for the exceptions where original date/time and new date/time are obligatory this time.

Related

Database Design for a Person's Availability

I am currently working on a web application that stores information of Cooks in the user table. We have a functionality to search the cooks from our web application. If a cook is not available on May 3, 2016, we want to show the Not-Bookable or Not-Available message for that cook if user performs the search for May 3, 2016. The solution we have come up to is to create a table named CooksAvailability with following fields
ID, //Primary key, auto increment
IDCook, //foreign key to user's table
Date, //date he is available on
AvailableForBreakFast, //bool field
AvailableForLunch, //bool field
AvailableForDinner, //book field
BreakFastCookingPrice, //decimal nullable
LunchCookingPrice, //decimal nullable
DinnerCookingPrice //decimal nullable
With this schema, we are able to tell if the user is available for a specific date or not. But the problem with this approach is that it requires a lot of db space i.e if a cook is available for 280 days/year, there has to be 280 rows to reflect just one cook's availability.
This is too much space given the fact that we may have potentially thousands of cooks registered with our application. As you can see the CookingPrice fields for breakfast, lunch and dinner. it means a cook can charge different cooking rates for cooking on different dates and times.
Currently, we are looking for a smart solution that fulfils our requirements and consumes less space than our solution does.
You are storing a record for each day and the main mistake, which led you to this redundant design was that you did not separate the concepts enough.
I do not know whether a cook has an expected rate for a given meal, that is, a price one can assume in general if one has no additional information. If that is the case, then you can store these default prices in the table where you store the cooks.
Let's store the availability and the specific prices in different tables. If the availability does not have to store the prices, then you can store availability intervals. In the other table, where you store the prices, you need to store only the prices which deviate from the expected price. So, you will have defined availability intervals in a table, specific prices when the price differs from the expected one in the oter and default meal price values in the cook table, so, if there is no special price, the default price will be used.
To answer your question I should know more about the structure of the information.
For example if most cooks are available in a certain period, it could be helpful to organize your availability table with
avail_from_date - avail_to_date, instead of a row for each day.
this would reduce the amount of rows.
The different prices for breakfast, lunch and dinner could be stored better in the cooks table, if the prices are not different each day. Same is for the a availability for breakfast, lunch and dinner if this is not different each day.
But if your information structure makes it necessary to keep a record for every cook every day this would be 365 * 280 = 102,200 records for a year, this is not very much for a sql db in my eyes. If you put the indexes at the right place this will have a good performance.
There are a few questions that would help with the overall answer.
How often does availability change?
How often does price change?
Are there general patterns, e.g. cook X is available for breakfast and lunch, Monday - Wednesday each week?
Is there a normal availability / price over a certain period of time,
but with short-term overrides / differences?
If availability and price change at different speeds, I would suggest you model them separately. That way you only need to show what has changed, rather than duplicating data that is constant.
Beyond that, there's a space / complexity trade-off to make.
At one extreme, you could have a hierarchy of configurations that override each other. So, for cook X there's set A that says they can do breakfast Monday - Wednesday between dates 1 and 2. Then also for cook X there's set B that says they can do lunch on Thursday between dates 3 and 4. Assuming that dates go 1 -> 3 -> 4 -> 2, you can define whether set B overrides set A or adds to it. This is the most concise, but has quite a lot of business logic to work through to interpret it.
At the other extreme, you just say for cook X between date 1 and 2 this thing is true (an availability for a service, a price). You find all things that are true for a given date, possibly bringing in several separate records e.g. a lunch availability for Monday, a lunch price for Monday etc.

SQL Schema - merge data from two tables

I'm trying to create a schema that will allow me to define times, when a supplier website is non operational (planned not unplanned).
I've gone for non-operational as opposed to operational because many suppliers work 24/7, so non-operting times represent the least number of rows.
For example, a supplier might not work:
On a Sunday
On a recognised holiday date - '1/1/2015'
On a Saturday after 5pm
I'm not overly confident with SQL Server, but have come up with a schema that 'does the job'. However, as we all know, there are good ways, not so good ways, and bad ways, that all work in a fashion, so would appreciate comments and advice on what I have to date.
One of the key features is to use data from WorkingDays and Holidays together to represent a WorkingPeriod entity.
I would appreciate coments no matter how small.
Holiday
Contains all recognised holidays - Easter Monday, Good Friday etc.
HolidayDate
Contains dates of holidays. For instance, this year Easter Monday is 6th Apr 2015.
WorkingDay
Sunday through to Monday, mapped to Asp.Net day of week enums.
WorkingPeriodType
A lookup table containing 2 rows - Holiday, or Day of Week
WorkingPeriod
Merges the Holiday table and the WorkingDay table to represent a single WorkingPeriod entity that can be used in the SupplierNonWorkingTimes table.
SupplierNonWorkingTimes
Contains the ID representing the WorkingDay/Holiday and the times of non- operation.
This is a very subjective question, as you've already observed there's no right and wrong, just different ways. I'm a database guy but I don't know your specific circumstances, so this is just some observations - you'll have to judge for yourself whether any of them are appropriate to you.
I like my naming to be crystal clear, it saves all the
misunderstanding by other people later on. If [WorkingDay] holds the
7 days of the week I would call it [WeekDay]. If you intend
[Holiday] to hold whole-day holidays I would call it [HolidayDay].
The main table [SupplierNonWorkingTime] is about 'non-working' so I
would call the [WorkingPeriod] table [NonWorkingPeriod]. The term
'period' always refers to a whole day, so I would replace 'period'
with 'day' (let's ignore start/stop time for now).
My first impression was that your design is over-normalised. The
[WorkingPeriodType] table has 2 rows that will never change,
[WorkingDay] has 7. For these very low numbers I sometimes prefer a
char(1) with a check constraint. Normalisation is generally good,
but lots of JOINs for trivial queries is not so good. You could
eliminate [WorkingPeriodType] and [WorkingDay] but you've mentioned
.Net enums in your question so if you've got some sort of ORM in
your .Net code this level of normalisation might be right for you.
I'd add a Year field to the [HolidayDate] table, then the PK
becomes a better HolidayID+Year - unless you know somewhere that has
lots of Christmas' :)
I'd add an IsAllDay field to the [SupplierNonWorkingTime] table,
otherwise you have to use 'magic values' to represent 'all day' and
magic values are bad. There should be a check constraint to enforce
start/stop times can only be entered if IsAllDay = false.
Like I said, just my thoughts, hope it's helpful.

Best practice database schema for property booking calendar

I am working on a multiple properties booking system and making me headache about the best practice schema design. Assume the site hosts for example 5000 properties where each of it is maintained by one user. Each property has a booking calendar. My current implementation is a two-table-system with one table for the available dates and the other for the unavailable dates, with a granularity of 1 day each.
property_dates_available (property_id, date);
property_dates_booked (property_id, date);
However, i feel unsure if this is a good solution. In another question i read about a single table solution with both states represented. But i wonder if it is a good idea to mix them up. Also, should the booking calendar be mapped for a full year with all its 365 days per year into the database table or was it better to map only the days a property is available for booking? I think of the dramatically increasing number of rows every year. Also i think of searching the database lately for available properties and am not sure if looking through 5000 * 365 rows might be a bad idea compared to i.e. only 5000 * av. 100 rows.
What would you generally recommend? Is this aspect ignorable? How to best practice implement this?
I don't see why you need a separate table for available dates. If you have a table for booked dates (property_id, date), then you can easily query this table to find out which properties are available for a given date
select properties.property_name
from properties where not exists
(select 1 from property_dates_booked
where properties.property_id = property_dates_booked
and property_dates_booked.date = :date)
:date being a parameter to the query
Only enter actual bookings into the property_dates_booked table (it would be easier to rename the table 'bookings'). If a property is not available for certain dates because of maintenance, then enter a booking for those dates where the customer is 'special' (maybe the 'customer' has a negative id).

How to store timetables?

I'm working on a project that must store employees' timetables. For example, one employee works Monday through Thursday from 8am to 2pm and from 4pm to 8pm. Another employee may work Tuesday through Saturday from 6am to 3pm.
I'm looking for an algorithm or a method to store these kind of data in a MySQL database. These data will be rarely accessed so it's not important performance questions.
I've thought to store it as a string but I don't know any algorithm to "encode" and "decode" this string.
As many of the comments indicate, it's usually a poor idea to encode all the data into a string that is basically meaningless to the data base. It's usually better to define the data elements and their relations and represent these structures in the data base. The Wikipedia article on data models is a good overview of what's involved (although it's way more general than what you need). The problem you are describing seems simple enough that you could do this with pencil and paper.
One way to start is to write down a lists of logical relationships between concepts in your problem. For instance, the list might look like this (your rules may be different):
Every employee follows a single schedule.
Every employee has a first and last name, as well as an employee ID. Different employees may have the same name, but each employee's ID is unique to that employee.
A schedule has a start and stop day of the week and a start and stop time of day.
The start and stop time is the same for every day of the schedule.
Several employees may be on the same schedule.
From this, you can list the nouns used in the rules. These are candidates for entities (columns) in the data base:
Employee
Employee ID
Employee first name
Employee last name
Schedule
Schedule start day
Schedule start time
Schedule end day
Schedule end time
For the rules I listed, schedules seem to exist independently of employees. Since there needs be a way of identifying which schedule an employee follows, it makes sense to add one more entity:
Schedule ID
If you then look at the verbs in the rules ("follows", "has", etc.), you start to get a handle on the relationships. I would group everything so far into two relationships:
Employees
ID
first_name
last_name
schedule_ID
Schedules
ID
start_day
start_time
end_day
end_time
That seems to be all that's needed by way of data structures. (A reasonable alternative to start_day and end_day for the Schedules table would be a boolean field for each day of the week.) The next step is to design the indexes. This is driven by the queries you expect to make. You might expect to look up the following:
What schedule is employee with ID=xyz following?
Who is at work on Mondays at noon?
What days have nobody at work?
Since employees and schedules are uniquely identified by their respective IDs, these should be the primary fields of their respective tables. You also probably want to have consistency rules for the data. (For instance, you don't want an employee on a schedule that isn't defined.) This can be handled by defining a "foreign key" relationship between the Employees.schedule_ID field and the Schedules.ID field, which means that Employees.schedule_ID should be indexed. However, since employees can share the same schedule, it should not be a unique index.
If you need to look up schedules by day of week and time of day, those might also be worth indexing. Finally, if you want to look up employees by name, those fields should perhaps be indexed as well.
Assuming you're using PHP:
Store a timetable in a php array and then use serialize function to transform it in a string;
to get back the array use unserialize.
However this form of memorization is almost never a good idea.

How to Implement Business Related Schedules in Relational Databases (e.g. Employee Schedules, Appointments, Courses and etc.)

I wasn't sure how I should word the title; I apologize if it is unclear. I’m developing a relational database for a vocational school. I want to provide students with their class schedules online. I would like to make the design as flexible as possible. I want to store exact dates and times including the term and year. I am interested in learning how any of you would approach this. Also I’m searching for a book, training video, tutorial or discussion on this specific topic.
The part I’m unsure of is how to have the amount of days vary from one schedule to another. I understand it is a one-to-many relationship; however, I’m unsure how I should set it up in this scenario. Also what about leap year?
My Approach is to make a Month/Day Table, Year Table and Term Table with foreign keys in a Schedule Table. To Address Leap Year I would just make the Month/Day Table 366 days. I’m unsure if this idea is overkill, I’m looking for the most elegant solution for handling any practical variation in a schedule.
I apologize if I’m way off, I’ve been trying to teach myself Relational Database Development but I’m just getting started.
I would like the schedule to output partly like this:
Example Class A Schedule:
01/02/2011 1:00pm-3:00pm
01/03/2011 2:00pm-4:00pm
01/04/2011 1:00pm-3:00pm
01/05/2011 2:00pm-5:00pm
01/08/2011 1:00pm-4:00pm
Example Class B Schedule:
01/02/2011 1:00pm-3:00pm
01/03/2011 2:00pm-4:00pm
Here are some of the business rules; they are similar to those of a college:
Class schedules must not be
constrained to any pattern
Class schedules must store every date
and time class is held
Class Schedules must include the
start and end time
Classes may or may-not be associated
with a term
Schedules may be created and stored
in the database long before the class
is offered
Students must be able to see the
schedules for classes offered
Students must be able to access
schedules for classes they are
registered for
I may or may not understand your business requirement, so this might be really bad advice. However, what I would say is don't create a table to hold days if the only thing in the table is a calendar, without any other attribution around the individual dates.
If your schedule is based on a rotating schedule of an arbitrary number of days, like "Day 1" to "Day 6" or the like, then this deserves its own table, then the occurences of classes become an intersection between the day of the rotation and the class. Each intersection would have a date and time as well as foreign keys to the class and rotation day.
Depending on your business rules, Terms might plug in either above the class or above the arbitrary day schedule. The Term table should probably include starting and ending dates, in any case.
You don't need to do anything special for leap years or days in a month etc, because SQL is smart enough to be able to work out date-related queries.
Can you tell me more about what your business rules are for setting up a schedule? If so, maybe I can hone my advice.
I came up with a design based on what you mentioned, I included it below.
* Primary Key
~ Foreign Key
Classes_Table
*ClassID
ClassName
ClassNumber
~ScheduleID
Schedules_Table
*ScheduleID
~ClassID
Class_Schedule_Table (There Would Be Many Of These Tables, 1 For Each ScheduleID)
*DayID
Date
StartTime
EndTime
~TermID
~ClassID
~ScheduleID
Terms_Table
*TermID
TermName
Students_Table
*StudentID
StudentName
Student_Schedules_Table
*RegistrationID
~StudentID
~ClassID
~ScheduleID

Resources