Oracle
 sql >> Database >  >> RDS >> Oracle

Qual è l'alternativa MySQL alla funzione NEXT_DAY di Oracle?

Ho intenzione di lanciare il mio cappello sul ring con l'ennesimo approccio:

Modifica: Mi rendo conto un po' tardivamente che la funzione Oracle in questione accetta una stringa come secondo argomento, e quindi questo non si adatta esattamente al requisito. Tuttavia MySQL ha già gentilmente definito 0 - 6 come lunedì - domenica, e comunque ho obiezioni morali all'utilizzo di una stringa come argomento per questo tipo di cose. Una stringa proverrebbe dall'input dell'utente o ancora un'altra mappatura nel codice di livello superiore tra valori numerici e stringa. Perché non passare un numero intero? :)

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

Per scomporre la parte che determina l'INTERVAL valore:

La prima parte dell'equazione ottiene semplicemente l'offset tra il giorno della settimana specificato e il giorno della settimana della data specificata:

p_weekday - WEEKDAY(p_date)

Questo restituirà un numero positivo se p_weekday è maggiore di WEEKDAY(p_date) e viceversa. Zero verrà restituito se sono uguali.

Il ROUND() segment viene utilizzato per determinare se il giorno della settimana richiesto (p_weekday ) è già avvenuto nella settimana corrente rispetto alla data (p_date ) specificato. Quindi, per esempio...

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

..restituisce 0 , indicando quella domenica (6 ) non si è verificato questa settimana, come 2019-01-25 è un venerdì. Allo stesso modo...

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

...restituisce 1 perché mercoledì (2 ) è già passato. Nota che questo restituirà 0 se p_weekday è lo stesso del giorno della settimana di p_date .

Questo valore (o 1 o 0 ) viene quindi moltiplicato per la costante 7 (il numero di giorni in una settimana).

Quindi se p_weekday è già avvenuto nella settimana corrente, aggiungerà 7 all'offset p_weekday - WEEKDAY(p_date) , perché quell'offset sarebbe un numero negativo e vogliamo una data futura.

Se p_weekday deve ancora verificarsi nella settimana corrente, quindi possiamo semplicemente aggiungere l'offset alla data corrente perché l'offset sarà un numero positivo. Da qui la sezione ROUND(...) * 7 è uguale a zero e, in sostanza, ignorato.

Il mio desiderio per questo approccio era simulare un IF() condizione matematicamente. Questo sarebbe ugualmente valido:

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

E nell'interesse dell'obiettività, nell'eseguire 1M iterazioni alcune volte di ciascuna funzione, il IF -based versione mediamente più veloce di circa il 4,2% rispetto a ROUND versione basata su.