Opening Hours Database Design - sql

We are currently developing an application in which multiple entities have associated opening hours. Opening hours may span multiple days, or may be contained within a single day.
Ex. Opens Monday at 6:00 and closes at Friday at 18:00.
Or
Opens Monday at 06:00 and closes Monday at 15:00.
Also, an entity may have multiple sets of opening hours per day.
So far, the best design I have found, is to define an opening hour to consist of the following:
StartDay, StartTime, EndDay and EndTime.
This design allows for all the needed flexibility. However, data integrity becomes an issue. I cannot seem to find a solution that will disallow overlapping spans (in the database).
Please share your thoughts.
EDIT: The database is Microsoft SQL Server 2008 R2

Consider storing your StartDay and StartTime, but then have a value for the number of hours that it's open. This will ensure that your closing datetime is after the opening.
OpenDate -- day of week? e.g. 1 for Monday
OpenTime -- time of day. e.g. 08:00
DurationInHours -- in hours or mins. e.g. 15.5

Presuming a robust trigger framework
On insert/update you would check if the new start or end date falls inside of any existing range. If it does then you would roll back the change.
CREATE TRIGGER [dbo].[mytable_iutrig] on [mytable] FOR INSERT, UPDATE AS
IF (SELECT COUNT(*)
FROM inserted, mytable
WHERE (inserted.startdate < mytable.enddate
AND inserted.startdate > mytable.startdate)
OR (inserted.enddate < mytable.enddate
AND inserted.enddate > mytable.startdate)) > 0
BEGIN
RAISERROR --error number
ROLLBACK TRANSACTION
END

Detecting and preventing overlapping time periods will have to be done at the application level. Of course you can attempt to use a trigger in the database but in my opinion this is not a database issue. The structure that you came up with is fine, but your application logic will have to take care of the overlap.

There's an article by Joe Celko on the SimpleTalk website, over here, that discusses a similar issue, and presents am elegant if complex solution. This is probably applicable to your situation.

A table with a single column TimeOfChangeBetweenOpeningAndClosing?
More seriously though, I would probably not worry too much about coming up with a single database structure for representing everything, eventually you'll probably want want a system involving recurrences, planned closures etc. Persist objects representing those, and then evaluate them to find out the closing/opening times.

This looks like a good solution, but you'll have to write a custom validation function. The built in database validation (i.e. unique, less than x, etc.) isn't going to cut it here. To ensure you don't have overlapping spans, every time you insert a record into the database, you're going to have to select existing records and compare...

First the logic, two spans will overlap if the start value of one falls between the start/end of the other. This is much easier if we have datetimes combined, instead of date1,time1 and date2,time2. So a query to find an overlap looks like this.
select openingId
from opening o1
join opening o2 on o1.startDateTime
between o2.startDateTime
AND o2.endDateTime
You can put this into a trigger and throw an error if a match is found.

Related

SQL query for inventory management

Hope I can explain the problem I'm having trouble with.
I have to write a stepwise methodology using pseudocode/SQL query to auto generate a list of products/items with low stock/expiry from the inventory database.The list must be updated at 12 a.m. daily.
I tried this
CREATE EVENT IF NOT EXISTS update_table
ON SCHEDULE EVERY 1 DAY STARTS '2022-05-22 00:00:00'
ON COMPLETION PRESERVE ENABLE
Do
Select inventory.products from inventory where inventory.stocks <
inventory.required_stocks.
Your stated requirement is to run some sort of report very soon after the beginning of each calendar day.
The next question you must answer is this: What will you do with that report? Will you simply drop it into "low_stock" table someplace in your database? Will you format it into an email message and send it to your purchasing department? It will be difficult to make "pseudocode" for your requirement without first analyzing the overall business process you intend to enhance.
Various RDBMS systems have ways of doing scheduled things at particular times of day. You've shown the EVENT setup provided by MariaDB / MySQL. SQL Server has their "Jobs" system. postgreSQL has the pg_cron extension. Yo
The thing is, you can't just do SELECT operations from within these scheduled database actions: the result sets have noplace to go from that context. You can do CREATE TABLE midnight_run AS SELECT whatever ... to place the results in a table. But then the results are in another table.
If you want to get the results out of the DBMS, you'll need a UNIXish cron job or a Windowsish scheduled task running an appropriate application at midnight each day.
Pro tip Do your best to avoid scheduling stuff for precisely midnight. Many things run then. If you wait until a couple of minutes after the hour, your code is less likely to contend with other midnight code.

How do I add new rows to SQL automatically by time?

I'm a pretty new programmer and I'm working on a project that I'm not sure how to make work. I'm hoping for some advice please.
Part of the project I'm working on will be used by a company to allow employees to sign up for lunch from their computers. I'm doing the project in MVC ASP.NET
The interface will look something like this:
----------------------
|1200 | Employee Dropdown Name 1
| Employee Dropdown Name 2
|---------------------
|1230 | Employee Dropdown Name 1
| Employee Dropdown Name 2
|---------------------
and on and on and on.
With this company, everything has to be recorded and stored. So, I already have a table with employee information. That will populate the drop down areas. Lunch times need to be stored in the database so it can be searched years down the line. So it has to be in a table.
The table get more tricky because not every time of the day is available for lunch (i.e. - no lunches after 0430 and before 0800).
My question is about how to create the future time slots in the database.
I could obviously make the table with all of these rows already in places for several years down the line. That's time-consuming, though, and I'll have to go back in in several years and fix it. Horrible idea.
What I'd LOVE to do is make it so every 24 hours, the database just automatically adds new rows with the next days times available - so just increment (at midnight, the program will just add the next day's times associated with that date (so at midnight on February 6, 2020, it will create February 7, 2020 0000, February 7, 2020 0030, etc. I've studied a lot but I'm still beside myself on how to make this work.
Thanks in advance everyone!!!
As I understand, you want to drive your interface from the database table so that the user can select Name 1 and Name 2 and a time slot and submit.
It sounds like you also want the available timeslots to be driven by the database also (ie, timeslot in table without names with it is availlable). This is not a good idea. As you mentioned, you would be inserting data that is not actually a record but a placeholder. That will be very confusing down the track when you come to query the data.
My approach would be to do the following:
* add NOT NULL constraints to all columns in your database (if your database supports this feature) or have your app complain very much about NULLS in any of the columns. There is no need for NULLS in your use case by the look of it.
the database should have a CHECK constraint that the time is within the allowable time range, and (assuming employees can not double book time slots) a CHECK constraint that there is no overlapping time slots, and also a UNIQUE constraint that ensures no duplicate times.... adjust to suit your needs.
your app populates times between 0800 and 1630 (8AM and 4:30PM) and also query the database for all records matching the current day so those booked slots can be removed from the list of available time slots... adjust to suit.
your app sends the user request of name and time slot to the DB. All the critical requirements are accepted or rejected by the DB schema and if there is something wrong, display an appropriate error in the app.
This way, your database is literally storing records of booked lunches.
I would NOT go down the path of pre inserting as then it becomes more complex as some records are "real" and some are artificially generated records to drive a GUI...
If you can't do the time slot calculations in your app rather than in the DB, then at least use a separate table that is maintained by a worker thread in your app OR if your DB supports it, a Stored Procedure which returns a table of available time slots.
I would use the stored procedure if I was avoiding doing complex time calculations in my app (also avoids need to worry about time zones - if you make sure to only store and display UTC times in your DB).
Having in mind structure like this:
LunchTimeSlots (id, time_slot)
Employee (id, name, preferred_time_slot_id, etc)
Lunches(employee_id, time_slot_id, date)
You need a scheduled job to add records to the "Lunches" table every midnight. How to define the job depends on your database vendor. But most of the popular rdbms have this feature. (f.e. mssql)
Despite it's possible to do what you want with db schedulers or any other scheduler, i would recommend to avoid such db design. It's always better to write real facts to the database like a list of employees or fact that lunch was served
to employee at 1pm today.
Unlike real facts, virtual data can be always generated "on-the-fly" by sql queries. F.e. by joining employees to list of dates from today till year 2100, we can get planned lunches for all employees for next 80 years.

pulling current date queue

I have a view that lists employee (EmpID), request number (ReqNo), date request was opened (OpenDate) and the date it was moved to the next step in the process (AssignDate). What I am trying to do is get an average of the daily queue size. If EmpID 001 has 20 requests on 1/1/13, then has 24 on 1/2/13, 21 on 1/3/13 the average over 3 days should be 21.66, rounded up to 22. I have the following view:
CREATE VIEW EmpReqs
AS
SELECT [EmpID], [OpenDate], [AssignDate], [ReqID]
FROM [Metrics].[dbo].[Assignments]
WHERE OpenDate BETWEEN '01/01/2013' AND '12/31/2013' AND
[EmpID] IS NOT NULL AND
[ReqNo] NOT LIKE 'M%'
I then wrote a query to pull individual employee's queues per day:
/* First attempt to generate daily queue #s */
SELECT * FROM BLReqs
WHERE [BusLiaison] LIKE 'PN' AND
[OpenDate] <= '11/15/2013' AND
[AssignDate] > '11/15/2013'
Because no one has attempted to pull this information before, I have no way of verifying how accurate the above is. I tried using current dates, since I can see those in our database to compare but the code doesn't work, nothing is returned when I change the dates to 2014 and run my query.
What is the easiest way to verify that my code is correct, short of manually counting a day's queue?
Can anyone see any issues with the above scripts?
Is there a way to get the above code to work with current dates?
This question is really hard to answer because it is kind of broad and has little information at the same time. I'll try anyway:
Because no one has attempted to pull this information before, I have
no way of verifying how accurate the above is.
Try checking the result of this query for a few sampled dates.
I tried using current dates, since I can see those in our database to
compare but the code doesn't work, nothing is returned when I change
the dates to 2014 and run my query.
So clearly, the query is not working. You should probably find out why. Run the query for a date of which you know that it should return results but doesn't. Remove conditions one by one to see which one is incorrectly removing all rows. This should be enough to identify the bug.
Can anyone see any issues with the above scripts?
No, looks fine. A very simple query. That's why I said that we have too little information. There is some key piece of information missing that allows us to find the bug.
Is there a way to get the above code to work with current dates?
Stop staring at the code and hoping for a revelation. Debug it. Experiment.

How to handle reoccurring calendar events and tasks (SQL Server tables & C#)

I need to scheduled events, tasks, appointments, etc. in my DB. Some of them will be one time appointments, and some will be reoccurring "To-Dos" which must be checked off. After looking a google's calendar layout and others, plus doing a lot of reading here is what I have so far.
Calendar table (Could be called schedule table I guess): Basic_Event Title, start/end, reoccurs info.
Calendar occurrence table: ties to schedule table, occurrence specific text, next occurrence date / time????
Looked here at how SQL Server does its jobs: http://technet.microsoft.com/en-us/library/ms178644.aspx
but this is slightly different.
Why two tables: I need to track status of each instance of the reoccurring task. Otherwise this would be much simpler...
so... on to the questions:
1) Does this seem like the proper way to go about it? Is there a better way to handle the multiple occurrence issue?
2) How often / how should I trigger creation of the occurrences? I really don't want to create a bunch of occurrences... BUT... What if the user wants to view next year's calendar...
Makes sense to have your schedule definition for a task in one table and then a separate table to record each instance of that separately - that's the approach I've taken in the past.
And with regards to creating the occurrences, there's probably no need to create them all up front. Especially when you consider tasks that repeat indefinitely! Again, the approach I've used in the past is to only create the next occurrence. When that instance is actioned, the next instance is then calculated and created.
This leaves the issue of viewing future occurrences. For this, you can start of with the initial/next scheduled occurrence and just calculate the future occurrences on-the-fly at display time.
While this isn't an exact answer to your question I've solved this problem before in SQL Server (though database here is irrelevant) by modeling a solution based on Unix's cron.
Instead of string parsing we used integer columns in a table to store the various time units.
We had events which could be scheduled; they could either point to a one-time schedule table that represented a distinct point in time (a date/time) or to the recurring schedule table which is modelled after cron.
Additionally remember to model your solution correctly. An event has a duration but the duration is unrelated to the schedule (but an event's duration may impact the schedule by causing conflicts). Do not try to model duration as part of your schedule.
In the past when we've done this, we had 2 tables:
1) Schedules -> Includes recurrence information
2) Exceptions -> Edit/changes to specific instances
Using SQL, it's possible to get the list of "Schedules" that have at least one instance in a given date range. Then you can expand in the GUI where each instance lies.

SQL Filtering based on Calculated Time Slots

Im making a simple booking system for our projectors at work.
Here is the scenario. Each projectors can have its availability set to quarter hour segments throughout the entire day. i.e projector 1 is available between 8:15am - 1:45pm and 3pm-5:15pm each day (can also be changed to have different availabilities set for each day). A projector can be booked for anytime time segment during the day as long as it is available. So ive got that setup in my sql database (with my asp.net mvc front end).
The question i have is what is the best way to search on this scenario. i.e. UserA comes in and says find me the projectors that are available this friday between 12pm-3pm. Im struggling to write an efficient sql query that will filter this. My best option so far is to pull back all projectors and than programatically work out if they are available and not booked between this time. It works but it is incredibly inefficient. I stumbled an idea of using a temp table generated by a stored proc that can than be filtered but it isnt quite there.
Has anyone got any ideas how i could approach this?
Thanks in advance
I would probably have a table called ProjectorReservations which contained a start time and end time (amongst other fields you might care about i.e. who is renting the projector).
Searching a projector would look something like this:
SELECT projectorName
FROM Projectors
WHERE NOT EXISTS
(SELECT 1 FROM ProjectorReservations
WHERE Projectors.projectorName = ProjectorReservations.projectorName
AND (ProjectorReservations.startTime < {end_time}
OR ProjectorReservations.endTime > {start_time}))
That pretty much checks to make sure no reservations start before the one you are looking for ends and vice versa. Obviously you will need to swap in your fields accordingly but that should give you the general idea