PL/SQL: Wochentage in Zeitraum dynamisch ermitteln

Heute möchte ich anhand eines Beispiels zeigen, wie man in PL/SQL unter Angabe eines Wochentags alle darauffolgenden Wochentage innerhalb eines Zeitraumes bestimmen und in der Datenbank speichern kann.

Für ein Projekt wurde eine APEX-Formularmaske benötigt, auf welcher der Webseiten-Administrator die Möglichkeit haben soll, einen oder mehrere Wochentage (montags, dienstags usw.) innerhalb eines Zeitraums auszuwählen sowie eine Uhrzeit und einen Coach anzugeben. Ziel war es, die Daten aller ausgewählten Wochentage zwischen Anfangs- und Enddatum mit PL/SQL zu berechnen und die Daten in der Datenbanktabelle appointments zu speichern. Endanwender können an diesen Tagen einen Support-Slot über eine separate Bestellmaske buchen.

Zuerst wird die Spezifikation des PL/SQL-Packages erzeugt:

Anschließend wird der zugehörige Package-Body generiert:

Für die ausgewählten Wochentage werden Doppelpunkt-getrennt Rückgabewerte (in Form von Nummerierungen, 0 (Montag) bis 4 (Freitag)) als Varchar2 aus der APEX-Seite an die Prozedur all_weekdays_in_period übergeben (z. B. ’0:1:3’ für Montag, Dienstag und Donnerstag). Über die Datenbankfunktion NEXT_DAY() wird das Datum des im zweiten Übergabeparameter übergebenen Wochentags(*) zurückgeliefert, der dem übergebenen Datum folgt. Als Beispiel würde NEXT_DAY('23-AUG-2020', 'SUNDAY') den nächsten Sonntag (30. August 2020) liefern, auch wenn es sich beim 23. August ebenfalls um einen Sonntag handelt. Damit auch der Starttag berücksichtigt werden kann, verwenden wir NEXT_DAY(<startdatum>-1, <wochentagsname>), um das Datum des Tages zu erhalten, das dem Startdatum vorangeht, und dieses für die Berechnungen zu nutzen. Nach der Ermittlung des Tagesdatums können durch einfache mathematische Multiplikationen mithilfe einer FOR-Schleife alle folgenden Wochentage bestimmt werden.

Bei der Abfrage der Tagesdaten sollen Feiertage nicht mitgespeichert werden. Um zu prüfen, ob ein Datum einen Feiertag repräsentiert, wird an dieser Stelle die im vorherigen Artikel beschriebene Funktion german_holidays_in_nw genutzt.

(*) Hinweis: Für die Nutzung der NEXT_DAY()-Funktion muss als Übergabeparameter die Bezeichnung des Wochentags übergeben werden. Dieser in-Parameter zur Bestimmung des zurückliefernden Wochentages hängt von der NLS_DATE_LANGUAGE der aufrufenden Sitzung ab, gleichzeitig erlaubt die Funktion nicht die freie Angabe von NLS-Werten. Aus diesem Grund kann der Aufruf NEXT_DAY('23-AUG-2020', 'SUNDAY') zum ORA-Fehler ORA-01846: not a valid day of the week führen, sofern innerhalb der Sitzung eine abweichende Sprache (als Englisch) für NLS_DATE_LANGUAGE gespeichert ist. Um die Funktion unabhängig zu verwenden und den Wochentagsnamen in der Sprache der Session zu erhalten, nutzen wir als Workaround trunc(sysdate, 'IW'), um den ersten Tag der Woche nach ISO-Standard zu erhalten (Montag) und addieren den gewünschten Wochentag mit pi_weekday drauf. Über die Berechnung +7*rec_days erhalten wir alle weiteren Vorkommen des jeweiligen Wochentages.

Verwandte Beträge:
Make NEXT_DAY() independent of the invoking session’s NLS_DATE_LANGUAGE (community.oracle.com)
Add optional NLS_DATE_LANGUAGE parameter to NEXT_DAY() (community.oracle.com)