Ich würde eine Appointment
Tabelle vorschlagen, in der die aktuellen Termine für jeden Arzt gespeichert sind. Wir können einige Einschränkungen auf dieser Tabelle hinzufügen , die die Terminstartzeiten begrenzen , um sogar zehn Minuten Zeiten (zB 9,00, 9,10, 9,20) sowie einige andere gesunde Menschenverstand Prüfungen hinzufügen , wie EndTime
nach StartTime
und Arzt kann nicht gleichzeitig zwei Termine haben Start . Angenommen, Sie möchten auch, dass Ärzte nur zwischen 9 und 17 Uhr arbeiten, da jeder eine gewisse Work-Life-Balance benötigt.
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);
Wir können einige Daten in diese Tabelle einfügen, um zu sehen, wie sie aussieht. Beachten Sie, dass die dritte Einfügung fehlschlägt, da sie durch unsere Einschränkung verhindert wird. Der Arzt kann nicht zwei Termine gleichzeitig haben.
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');
Nehmen wir an, Sie haben eine Zahlentabelle. Wenn Sie nicht viele andere Leute beschrieben haben, wie man eine erstellt. Wenn alles andere fehlschlägt, könnte dies eine für Sie erstellen, aber es ist wahrscheinlich nicht der beste Weg.
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
Wenn wir nun freie Slots für einen bestimmten Arzt sehen möchten, müssen wir nur angeben, welcher Arzt und wie lange der Slot ist, den wir suchen:
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;
Das sieht etwas umständlich aus. Wenn also jemand diese Datumslogik verbessern kann, nimmt er gerne Vorschläge entgegen.
Wenn ein Arzt eine Pause wünscht, geben Sie die Pause als Termin ein und sie kann nicht gebucht werden.
Beachten Sie, dass die Tabelleneinschränkungen keine nicht überlappenden Termine erzwingen. Dies ist möglich, aber komplizierter. Wenn dies mein System wäre, würde ich über ein System (z. B. Auslöser) nachdenken, um endgültig zu überprüfen, ob sich der Termin zum Zeitpunkt des Einfügens nicht mit einem vorhandenen überschneidet, aber das liegt bei Ihnen.