Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Was ist die MySQL-Alternative zur NEXT_DAY-Funktion von Oracle?

Ich werde meinen Hut mit einem weiteren Ansatz in den Ring werfen:

Bearbeiten: Etwas verspätet stelle ich fest, dass die fragliche Oracle-Funktion als zweites Argument einen String akzeptiert und dies daher nicht genau zur Anforderung passt. MySQL hat jedoch freundlicherweise 0 - 6 als Montag - Sonntag definiert, und ich habe sowieso moralische Einwände gegen die Verwendung eines Strings als Argument für diese Art von Dingen. Eine Zeichenfolge würde entweder aus Benutzereingaben stammen oder noch eine weitere Zuordnung in Code höherer Ebene zwischen numerischen und Zeichenfolgenwerten. Warum nicht eine Ganzzahl übergeben? :)

CREATE FUNCTION `fnDayOfWeekGetNext`(
        p_date DATE,
        p_weekday TINYINT(3)
        ) RETURNS date
BEGIN

        RETURN DATE_ADD(p_date, INTERVAL p_weekday - WEEKDAY(p_date) + (ROUND(WEEKDAY(p_date) / (p_weekday + WEEKDAY(p_date) + 1)) * 7) DAY);

END

Um den Teil aufzuschlüsseln, der das INTERVAL bestimmt Wert:

Der erste Teil der Gleichung erhält einfach den Offset zwischen dem angegebenen Wochentag und dem Wochentag des angegebenen Datums:

p_weekday - WEEKDAY(p_date)

Dies gibt eine positive Zahl zurück, wenn p_weekday ist größer als WEEKDAY(p_date) und umgekehrt. Null wird zurückgegeben, wenn sie gleich sind.

Das ROUND() Segment wird verwendet, um festzustellen, ob der angeforderte Wochentag (p_weekday ) ist in der aktuellen Woche relativ zum Datum (p_date) bereits aufgetreten ) spezifizierten. Also, zum Beispiel...

ROUND(WEEKDAY('2019-01-25') / (6 + WEEKDAY('2019-01-25') + 1))

..gibt 0 zurück , was darauf hinweist, dass Sonntag (6 ) ist diese Woche nicht aufgetreten, da 2019-01-25 ist ein Freitag. Ebenso...

ROUND(WEEKDAY('2019-01-25') / (2 + WEEKDAY('2019-01-25') + 1))

...gibt 1 zurück denn Mittwoch (2 ) ist bereits abgelaufen. Beachten Sie, dass dies 0 zurückgibt wenn p_weekday ist derselbe wie der Wochentag von p_date .

Dieser Wert (entweder 1 oder 0 ) wird dann mit der Konstante 7 multipliziert (die Anzahl der Tage in einer Woche).

Wenn also p_weekday bereits in der aktuellen Woche aufgetreten ist, wird 7 zum Offset p_weekday - WEEKDAY(p_date) hinzugefügt , da dieser Offset eine negative Zahl wäre und wir ein Datum in der Zukunft wünschen.

Wenn p_weekday in der aktuellen Woche noch nicht aufgetreten ist, können wir den Offset einfach zum aktuellen Datum addieren, da der Offset eine positive Zahl ist. Daher der Abschnitt ROUND(...) * 7 gleich Null ist und im Wesentlichen ignoriert wird.

Mein Wunsch für diesen Ansatz war, ein IF() zu simulieren Bedingung mathematisch. Dies wäre gleichermaßen gültig:

RETURN DATE_ADD(p_date, INTERVAL p_weekday - WEEKDAY(p_date) + IF(p_weekday - WEEKDAY(p_date) < 0, 7, 0) DAY);

Und im Interesse der Objektivität, beim Ausführen von 1M Iterationen ein paar Mal von jeder Funktion den IF -basierte Version im Durchschnitt etwa 4,2 % schneller als die ROUND -basierte Version.