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.