Jeg vil kaste min hat i ringen med endnu en tilgang:
Rediger: Jeg indser noget forsinket, at den pågældende Oracle-funktion tager en streng som det andet argument, og derfor passer dette ikke præcist til kravet. Men MySQL har allerede venligt defineret 0 - 6 som mandag - søndag, og alligevel har jeg moralske indvendinger mod at bruge en streng som argument for denne type ting. En streng ville enten komme fra brugerinput eller endnu en kortlægning i kode på højere niveau mellem numeriske og strengværdier. Hvorfor ikke videregive et heltal? :)
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
For at opdele den del, der bestemmer INTERVAL værdi:
Den første del af ligningen får simpelthen forskydningen mellem den angivne ugedag og ugedagen på den angivne dato:
p_weekday - WEEKDAY(p_date)
Dette vil returnere et positivt tal, hvis p_weekday er større end WEEKDAY(p_date) og omvendt. Nul vil blive returneret, hvis de er de samme.
ROUND() segment bruges til at bestemme, om den ønskede ugedag (p_weekday ) er allerede fundet sted i den aktuelle uge i forhold til datoen (p_date ) angivet. Så for eksempel...
ROUND(WEEKDAY('2019-01-25') / (6 + WEEKDAY('2019-01-25') + 1))
..returnerer 0 , hvilket angiver den søndag (6 ) har ikke fundet sted i denne uge, som 2019-01-25 er en fredag. Ligeledes...
ROUND(WEEKDAY('2019-01-25') / (2 + WEEKDAY('2019-01-25') + 1))
... returnerer 1 fordi onsdag (2 ) er allerede bestået. Bemærk, at dette vil returnere 0 hvis p_weekday er den samme som ugedagen p_date .
Denne værdi (enten 1 eller 0 ) ganges derefter med konstanten 7 (antal dage i en uge).
Derfor hvis p_weekday allerede har fundet sted i den aktuelle uge, vil det tilføje 7 til offset p_weekday - WEEKDAY(p_date) , fordi den forskydning ville være et negativt tal, og vi ønsker en dato i fremtiden.
Hvis p_weekday endnu ikke har fundet sted i den aktuelle uge, så kan vi bare tilføje forskydningen til den aktuelle dato, fordi forskydningen vil være et positivt tal. Derfor afsnittet ROUND(...) * 7 er lig med nul og i det væsentlige ignoreret.
Mit ønske med denne tilgang var at simulere en IF() tilstand matematisk. Dette ville være lige så gyldigt:
RETURN DATE_ADD(p_date, INTERVAL p_weekday - WEEKDAY(p_date) + IF(p_weekday - WEEKDAY(p_date) < 0, 7, 0) DAY);
Og af hensyn til objektiviteten er IF ved at køre 1M iterationer et par gange af hver funktion. -baseret version var i gennemsnit omkring 4,2 % hurtigere end ROUND -baseret version.