Je vais jeter mon chapeau dans le ring avec encore une autre approche :
Modifier : Je me rends compte un peu tardivement que la fonction Oracle en question prend une chaîne comme deuxième argument, et donc cela ne correspond pas précisément à l'exigence. Cependant, MySQL a déjà gentiment défini 0 - 6 comme lundi - dimanche, et de toute façon j'ai des objections morales à l'utilisation d'une chaîne comme argument pour ce type de chose. Une chaîne proviendrait soit de l'entrée de l'utilisateur ou encore un autre mappage dans le code de niveau supérieur entre les valeurs numériques et les valeurs de chaîne. Pourquoi ne pas passer un entier ? :)
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
Pour décomposer la partie qui détermine l'INTERVAL
valeur :
La première partie de l'équation obtient simplement le décalage entre le jour de la semaine spécifié et le jour de la semaine de la date spécifiée :
p_weekday - WEEKDAY(p_date)
Cela renverra un nombre positif si p_weekday
est supérieur à WEEKDAY(p_date)
et vice versa. Zéro sera renvoyé s'ils sont identiques.
Le ROUND()
segment est utilisé pour déterminer si le jour de la semaine demandé (p_weekday
) s'est déjà produit dans la semaine en cours par rapport à la date (p_date
) spécifié. Alors, par exemple...
ROUND(WEEKDAY('2019-01-25') / (6 + WEEKDAY('2019-01-25') + 1))
..renvoie 0
, indiquant que dimanche (6
) n'a pas eu lieu cette semaine, car 2019-01-25
est un vendredi. De même...
ROUND(WEEKDAY('2019-01-25') / (2 + WEEKDAY('2019-01-25') + 1))
... renvoie 1
car mercredi (2
) est déjà passé. Notez que cela renverra 0
si p_weekday
est le même que le jour de la semaine de p_date
.
Cette valeur (soit 1
ou 0
) est ensuite multiplié par la constante 7
(le nombre de jours dans une semaine).
Donc si p_weekday
s'est déjà produit dans la semaine en cours, il ajoutera 7 au décalage p_weekday - WEEKDAY(p_date)
, car ce décalage serait un nombre négatif et nous voulons une date dans le futur.
Si p_weekday
n'a pas encore eu lieu dans la semaine en cours, alors nous pouvons simplement ajouter le décalage à la date actuelle car le décalage sera un nombre positif. D'où la section ROUND(...) * 7
est égal à zéro et, par essence, ignoré.
Mon souhait pour cette approche était de simuler un IF()
condition mathématiquement. Ce serait tout aussi valable :
RETURN DATE_ADD(p_date, INTERVAL p_weekday - WEEKDAY(p_date) + IF(p_weekday - WEEKDAY(p_date) < 0, 7, 0) DAY);
Et dans un souci d'objectivité, en exécutant 1 million d'itérations plusieurs fois de chaque fonction, le IF
- la version basée était en moyenne environ 4,2 % plus rapide que la version ROUND
- version basée.