7

I am trying to make a doctor appointment system where patient online will have two options:

  1. First time visit (this visit should be 20 mins)
  2. Follow up visit (this visit should be 10 mins)

Constraints:

  1. Price will be different based on wither its a first time/follow up
  2. Doctor might have break times between slots
  3. System interface will support both options when booking the slot
  4. we need the least gap time between slots to make max. usage of doctors availability

The model we finished so far was based on creating a Doctor Slot table that's like the below Doctor Slots Table Schema

Consider the below Example if DoctorSlot is N and N=10 mins

Case First Time if(N*2)== Free Make reservation block two slots instead of one

Case Follow Up if(N)==Free Make Reservation Block one slot

Example Doctor: 9:00 to 9:10 Doctor: 9:10 to 9:20 Doctor: 9:20 to 9:30

Case First Time Show to patient 9:00 to 9:20

Challenges:

  • Append time from 9:00 to 9:20 (there could be a buffer time (break for doctor) between slots for doctors)
  • We will have two slot IDs from database instead of one (which SlotID will be used with Order)
  • How to show user in run time based on his case which time generic model we will use and update prices later on accordingly
  • If user booked a first time slot, then another user booked a follow up, there will be gaps and how to handle time in SQL Server in database

Questions:

  1. What is the best database schema to achieve a solution that satisfy all possible scenarios?
  2. What is the best method to deal with time entity from SQL Server/ASP.NET POV?
4

I would suggest an Appointment table which stores the current appointments for each doctor. We can add some constraints on this table which limit the appointment start times to even ten-minute times (e.g. 9.00, 9.10, 9.20) plus add some other common sense checks like EndTime after StartTime and doctor can't have two appointments starting at the same time. Assume that you'd also like doctors to only work between 9am and 5pm, because everyone needs some work-life balance.

CREATE TABLE Appointment (
    DoctorID char(1) NOT NULL,
    [Date] date NOT NULL,
    StartTime time(0) NOT NULL CONSTRAINT CHK_StartTime_TenMinute CHECK (DATEPART(MINUTE, StartTime)%10 = 0 AND DATEPART(SECOND, StartTime) = 0),
    EndTime time(0) NOT NULL CONSTRAINT CHK_EndTime_TenMinute CHECK (DATEPART(MINUTE, EndTime)%10 = 0 AND DATEPART(SECOND, EndTime) = 0),
    Status char(1) NOT NULL,
    UserID char(1) NOT NULL,
    Price int NOT NULL,
    CONSTRAINT PK_Appointment PRIMARY KEY CLUSTERED (DoctorID, [Date], StartTime),
    CONSTRAINT CHK_StartTime_BusinessHours CHECK (DATEPART(HOUR, StartTime) > = 9 AND DATEPART(HOUR, StartTime) < = 16),
    CONSTRAINT CHK_EndTime_BusinessHours CHECK (DATEPART(HOUR, EndTime) > = 9 AND DATEPART(HOUR, DATEADD(SECOND, -1, EndTime)) < = 16),
    CONSTRAINT CHK_EndTime_After_StartTime CHECK (EndTime > StartTime));
CREATE INDEX iDoctor_End ON Appointment (DoctorID, [Date], EndTime);

We can insert some data to this table to see what it looks like. Note that the third insert will fail because it is prevented by our constraint. The doctor can't have two appointments starting at the same time.

INSERT INTO Appointment VALUES ('A', '20170420', '09:00:00', '09:10:00', 'P', '1', '0');
INSERT INTO Appointment VALUES ('A', '20170420', '09:20:00', '09:40:00', 'C', '2', '10');
INSERT INTO Appointment VALUES ('A', '20170420', '09:00:00', '09:20:00', 'C', '2', '10');

Let's assume that you have a numbers table. If you don't many other people have described how to create one. If all else fails, this could create one for you but it's probably not the best way.

CREATE TABLE Numbers (Number int PRIMARY KEY CLUSTERED);
DECLARE @number int = 0;
WHILE @number < 1000
BEGIN
    INSERT INTO Numbers VALUES (@number);
    SET @number += 1;
END 

Now if we want to see free slots for a particular doctor, all we need to do is specify which doctor, and how long the slot is that we're looking for:

DECLARE @doctorID char(1) = 'A';
DECLARE @length tinyint = 20;
WITH Slots AS (
    SELECT StartTime = DATEADD(MINUTE, ((DATEPART(MINUTE, GETDATE())/10)+1+Number)*10, DATEADD(HOUR, DATEPART(HOUR, GETDATE()), CONVERT(smalldatetime, CONVERT(date, GETDATE())))),
           EndTime = DATEADD(MINUTE, @length, DATEADD(MINUTE, ((DATEPART(MINUTE, GETDATE())/10)+1+Number)*10, DATEADD(HOUR, DATEPART(HOUR, GETDATE()), CONVERT(smalldatetime, CONVERT(date, GETDATE())))))
      FROM Numbers)
SELECT TOP 15 DoctorID = @doctorID,
    s.StartTime,
    s.EndTime
  FROM Slots AS s
  WHERE NOT EXISTS (SELECT 1 
                      FROM Appointment AS a
                      WHERE (CONVERT(time(0), s.StartTime) < a.EndTime AND CONVERT(time(0), s.EndTime) > a.StartTime)
                        AND a.DoctorID = @doctorID
                        AND a.[Date] = CONVERT(date, s.StartTime))
    AND DATEPART(HOUR, s.StartTime) >= 9
    AND DATEPART(HOUR, DATEADD(MINUTE, -1, s.EndTime)) <= 16
ORDER BY s.StartTime;

That looks a little awkward, so if anyone can improve that date logic happy to take suggestions.

If a doctor wants a break, then enter the break as an appointment and it won't be available for booking.

Note that the table constraints don't enforce non-overlapping appointments. This is possible but it's more complicated. If this were my system I'd think about some system (e.g. trigger) to finally verify that the appointment doesn't overlap with an existing one at the time of insert, but that's up to you.

  • although I've solved this problem because its an old question and I used a different approach, but your answer is exactly what I were looking for. thanks for help :) – theK Apr 19 '17 at 6:33
  • 1
    @user3291143 Yes, I noted that it's an old question, but it was bumped up to the front page so I thought it was worth taking a shot at a more thorough answer for future reference. Thanks for responding. – mendosi Apr 19 '17 at 6:38
  • @theK.please share your code how you done – iCoders Aug 21 '18 at 3:10
0

First of all, why is your time slot of fixed length? Even with current design, you can have a slot with start_time = 9:00 and end_time = 9:20, and it can be one id. Furthermore, you can make a bridge table to connect type of exams (i.e. type 1 = first exam, type 2 = control exam etc) to length of slots, like this:
exam_type slot_length_in_minutes
1 20
2 10
3 15
In this case, when you book time for the exam, in the UI you would select an exam type from some kind of select box (combo-box) and and then search for a free slot of appropriate size.

Also you didn't give us your reservations table structure, so we can help you with that. But I guess you have some sort of time slot id there, and also the id of a selected doctor...? In that case, just by joining time slots and reservations could show you the complete timetable. Hope it was of any help. If not, feel free to ask more.

  • I want this free slot of appropriate size to be changed dynamically based on the type the user chose, for example if user chose "first time appointment" then he should be able to see slots for 20 mins length but if he chose "2nd time appointment'' he should see a 10 mins length slots – theK May 16 '16 at 20:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.