Suppose there is database table structure as follows. Aim of the application is to have a scheduling tool based based on rotating weeks. For example, a customer will have scheduled appointments from 1 Jan 2021 till 31 Dec 2021, with the first week an appoint every Monday 8am - 10am and friday 9am-11am, and every second week every Tuesday 1pm - 4pm.
Period WeekRotations Appointments
------ ------------- --------------
ID (PK, int)<--\ ID (PK, int)<--\ ID (PK, int)
DateStart (date) \-->PeriodID (FK, int) \->WeekRotationID (FK, int)
DateEnd (date) SequenceNr (int) DayOfWeek (int)
CustomerID (FK, int) TimeStart (datetime)
TimeEnd (datetime)
So the 'Period' table holds the relation to the customer, and defines the period the appointment should be scheduled. It can be an infinite list for any customer, but never overlaps for a customer. For the above example this would be:
ID DateStart DateEnd CustomerID
10 2020-01-01 2020-12-31 99
Data for the WeekRotations for the above example would be the following. There can be an unlimited amount of weekrotations.
ID PeriodID SequenceNr
100 10 1
101 10 2
Data for the Appointments for the above example would be:
ID WeekRotationID DayOfWeek TimeStart TimeEnd
500 100 0 (=monday) 1900-01-01 08:00 1900-01-01 10:00
501 100 5 (=friday) 1900-01-01 09:00 1900-01-01 11:00
502 101 1 (=tuesday) 1900-01-01 13:00 1900-01-01 16:00
The only solution we have for the moment is to get the appointments for a given day by doing a SELECT with an inner join on all and:
WHERE SequenceNr= ABS(NrOfWeeksFromStartdate % NrOfWeekRotations) + 1
and where NrOfWeeksFromStartDate is calculated as follows:
SELECT CONVERT(int, FLOOR(DATEDIFF( d, [dbo].[GetPrevMonday](CONVERT(DATETIME, '2020-01-01', 102)), [dbo].[GetPrevMonday](DateStart)) / CONVERT( float, 7))) AS NrOfWeeksFromStartdate
However this results in a fairly complex sql query, and morever this is not efficient, as we have to loop over the entire year and query every day one by one!
Is there any way to get the list of actual dates and times of the actual appointments in a single query?
---------- EDIT ----------------------------------
This is a simplified sql statement example of what we are using currently. So if we need the appointments for a whole year, we have to execute this statement 365 times. This offcourse isn't efficient, and we want to do this in one single query.
SELECT * FROM (
SELECT
CONVERT(int, FLOOR(DATEDIFF( d, [dbo].[GetPrevMonday](CONVERT(DATETIME, '2021-01-01', 102)), [dbo].[GetPrevMonday](DateStart)) / CONVERT( float, 7))) AS NrOfWeeksFromStartdate,
(SELECT COUNT(WeekRotations.ID) FROM WeekRotations WHERE PeriodID=Periods.ID) AS NrOfWeekRotations,
*
FROM
Customers INNER JOIN Periods ON Customers.ID=Periods.CustomerID
INNER JOIN WeekRotations ON Periods.ID=WeekRotations.PeriodID
INNER JOIN Appointments ON Appointments.WeekRotationID = WeekRotations.ID
WHERE
CONVERT(DATETIME, '2021-01-01', 102) BETWEEN DateStart AND DateEnd
AND DayOfWeek=4
) TBL
WHERE SequenceNr = ABS(NrOfWeeksFromStartdate % NrOfWeekRotations) + 1
---------- EDIT 2 ---------------------------------- GetPrevMonday function
CREATE FUNCTION [dbo].[GetPrevMonday]
(
@INPUTDATE DATETIME
)
RETURNS DATETIME
AS
BEGIN
DECLARE @DOW INT
SET @INPUTDATE = CONVERT(VARCHAR(10), @INPUTDATE, 111)
SET @DOW = DATEPART(DW, @INPUTDATE)
SET @DOW = (@DOW + @@DATEFIRST - 1) %7
IF @DOW = 0 SET @DOW = 7
RETURN DATEADD(DD, 1 - @DOW,@INPUTDATE)
END
GO
---------- EDIT 3 ---------------------------------- ---------- EXAMPLES --------------------------------
One appointment each monday for Q1 2021:
Periods
ID DateStart DateEnd CustomerID
1 2021-1-1 2021-3-31 1
WeekRotations
ID PeriodID SequenceNr
100 1 1
Appointments
ID WeekRotationID DayOfWeek TimeStart TimeEnd
500 100 0 (=monday) 1900-01-01 08:00 1900-01-01 10:00
------------
One appointment every other monday for Q1 2021:
Periods
ID DateStart DateEnd CustomerID
1 2021-1-1 2021-3-31 1
WeekRotations
ID PeriodID SequenceNr
100 1 1
101 1 2
Appointments
ID WeekRotationID DayOfWeek TimeStart TimeEnd
500 100 0 (=monday) 1900-01-01 08:00 1900-01-01 10:00
------------
One appointment every 3 weeks on monday for Q1 2021:
Periods
ID DateStart DateEnd CustomerID
1 2021-1-1 2021-3-31 1
WeekRotations
ID PeriodID SequenceNr
100 1 1
101 1 2
102 1 3
Appointments
ID WeekRotationID DayOfWeek TimeStart TimeEnd
500 100 0 (=monday) 1900-01-01 08:00 1900-01-01 10:00