Hodím klobouk do ringu s ještě jiným přístupem:
Upravit: Poněkud opožděně si uvědomuji, že dotyčná funkce Oracle bere řetězec jako druhý argument, a tak to přesně neodpovídá požadavku. MySQL však již laskavě definovalo 0 - 6 jako pondělí - neděle a každopádně mám morální námitky proti použití řetězce jako argumentu pro tento typ věcí. Řetězec by pocházel buď z uživatelského vstupu nebo další mapování v kódu vyšší úrovně mezi číselnými a řetězcovými hodnotami. Proč nepředat celé číslo? :)
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
Rozdělit část, která určuje INTERVAL hodnota:
První část rovnice jednoduše získá posun mezi zadaným dnem v týdnu a dnem v týdnu zadaného data:
p_weekday - WEEKDAY(p_date)
Toto vrátí kladné číslo, pokud p_weekday je větší než WEEKDAY(p_date) a naopak. Pokud jsou stejné, bude vrácena nula.
ROUND() segment se používá k určení, zda požadovaný den v týdnu (p_weekday ) již došlo v aktuálním týdnu vzhledem k datu (p_date ) specifikováno. Takže například...
ROUND(WEEKDAY('2019-01-25') / (6 + WEEKDAY('2019-01-25') + 1))
..vrací 0 , což označuje tu neděli (6 ) tento týden nenastal, jako 2019-01-25 je pátek. Stejně tak...
ROUND(WEEKDAY('2019-01-25') / (2 + WEEKDAY('2019-01-25') + 1))
...vrací 1 protože středa (2 ) již prošel. Všimněte si, že to vrátí 0 pokud p_weekday je stejný jako den v týdnu p_date .
Tato hodnota (buď 1 nebo 0 ) se pak vynásobí konstantou 7 (počet dní v týdnu).
Pokud tedy p_weekday již došlo v aktuálním týdnu, přidá 7 k offsetu p_weekday - WEEKDAY(p_date) , protože tento posun by byl záporné číslo a my chceme datum v budoucnosti.
Pokud p_weekday ještě nenastane v aktuálním týdnu, pak můžeme jen přidat posun k aktuálnímu datu, protože posun bude kladné číslo. Proto sekce ROUND(...) * 7 se rovná nule a v podstatě se ignoruje.
Mým přáním tohoto přístupu bylo simulovat IF() podmínka matematicky. To by bylo stejně platné:
RETURN DATE_ADD(p_date, INTERVAL p_weekday - WEEKDAY(p_date) + IF(p_weekday - WEEKDAY(p_date) < 0, 7, 0) DAY);
A v zájmu objektivity při spuštění 1M iterací několikrát každé funkce IF -založená verze byla v průměru o 4,2 % rychlejší než ROUND -založená verze.