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.
Hier ist eine funktional äquivalente (und IMO leichter zu lesende) Version von Mendosis Code für MariaDB / MySQL mit einigen zusätzlichen Darstellungen und einer leicht vereinfachten Logik in einigen Bereichen.
Erstellen Sie eine
Numbers
Tabelle, falls Sie noch keine haben:Hier ist ein ausreichendes Schema für eine
Appointment
Tabelle. InINSERT
Kürze werden wir auch einen Trigger hinzufügen , der sicherstellt, dass neue Einträge nicht mit vorhandenen Einträgen in Konflikt geraten.Zunächst definieren wir eine Funktion, um zu bestimmen, ob ein bestimmtes Zeitfenster als neuer Termin zugewiesen werden kann:
Hier ist der
INSERT
zuvor erwähnte Auslöser, um sicherzustellen, dass keine Kollisionstermine gespeichert werden:Nachdem die
Appointment
Tabelle ordnungsgemäß eingerichtet wurde, können wir einige gültige Beispieleinträge einfügen:Wenn Sie versuchen, einen ungültigen Termineintrag einzufügen, wird aufgrund des
ensureNewAppointmentsDoNotClash
Auslösers ein Fehler ausgegeben. Tatsächlich löst dieser Trigger einen Fehler aus, noch bevor die Primärschlüsseleinschränkung überprüft wird, sodass dies als redundant angesehen werden kann. Für meine Lösung habe ich mich für ein ID-Feld für dieAppointment
Tabelle entschieden, anstatt einen zusammengesetzten Primärschlüssel zu verwenden.Hier ist das Verfahren, um mit einem bestimmten Arzt eine Ergebnismenge verfügbarer Zeitfenster einer bestimmten Länge zu erhalten. Beachten Sie, dass wir unsere
slotIsAvailable
zuvor definierte und auch in unseremINSERT
Trigger verwendete Funktion verwenden .Die obige Abfrage mit den obigen Beispieldatensätzen für
Appointment
und mit@searchStart
gleich'2019-10-06 06:00'
ergibt:quelle
Zunächst einmal, warum ist Ihr Zeitfenster von fester Länge? Selbst mit dem aktuellen Design können Sie einen Slot mit start_time = 9:00 und end_time = 9:20 haben, und es kann eine ID sein. Darüber hinaus können Sie eine Brückentabelle
erstellen, um den Prüfungstyp (dh Typ 1 = erste Prüfung, Typ 2 = Kontrollprüfung usw.) wie folgt mit der Länge der Zeitnischen zu verbinden : Prüfungstyp slot_length_in_minutes
1 20
2 10
3 15
In diesem Fall, wenn Sie Buchen Sie die Zeit für die Prüfung. Wählen Sie in der Benutzeroberfläche einen Prüfungstyp aus einem Auswahlfeld (Kombinationsfeld) aus und suchen Sie dann nach einem freien Platz mit der entsprechenden Größe.
Außerdem haben Sie uns Ihre Reservierungstabellenstruktur nicht mitgeteilt, damit wir Ihnen dabei helfen können. Aber ich denke, Sie haben dort eine Art Zeitfenster-ID und auch die ID eines ausgewählten Arztes ...? In diesem Fall können Sie durch den Beitritt zu Zeitfenstern und Reservierungen den vollständigen Zeitplan anzeigen. Ich hoffe, es hat geholfen. Wenn nicht, können Sie gerne mehr fragen.
quelle