Ще хвърля шапката си на ринга с още един подход:
Редактиране: С малко закъснение разбирам, че въпросната функция на Oracle приема низ като втори аргумент и така това не отговаря точно на изискването. Въпреки това MySQL вече любезно е дефинирал 0 - 6 като понеделник - неделя и така или иначе имам морални възражения срещу използването на низ като аргумент за този тип неща. Низът идва или от потребителско въвеждане или още едно картографиране в код от по-високо ниво между числови и низови стойности. Защо не подадете цяло число? :)
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
За да разделите частта, която определя INTERVAL
стойност:
Първата част от уравнението просто получава отместването между посочения ден от седмицата и деня от седмицата на посочената дата:
p_weekday - WEEKDAY(p_date)
Това ще върне положително число, ако p_weekday
е по-голямо от WEEKDAY(p_date)
и обратно. Ще бъде върната нула, ако са еднакви.
ROUND()
сегмент се използва за определяне дали исканият ден от седмицата (p_weekday
) вече се е случило през текущата седмица спрямо датата (p_date
) посочено. И така, като пример...
ROUND(WEEKDAY('2019-01-25') / (6 + WEEKDAY('2019-01-25') + 1))
..връща 0
, указващ тази неделя (6
) не се е случило тази седмица, тъй като 2019-01-25
е петък. По същия начин...
ROUND(WEEKDAY('2019-01-25') / (2 + WEEKDAY('2019-01-25') + 1))
...връща 1
защото сряда (2
) вече е минало. Имайте предвид, че това ще върне 0
ако p_weekday
е същият като деня от седмицата на p_date
.
Тази стойност (или 1
или 0
) след това се умножава по константата 7
(броя дни в седмицата).
Следователно, ако p_weekday
вече се е случило през текущата седмица, то ще добави 7 към отместването p_weekday - WEEKDAY(p_date)
, тъй като това отместване би било отрицателно число и ние искаме дата в бъдещето.
Ако p_weekday
все още не се е случило през текущата седмица, тогава можем просто да добавим отместването към текущата дата, защото отместването ще бъде положително число. Оттук и секцията ROUND(...) * 7
е равно на нула и по същество се игнорира.
Желанието ми за този подход беше да симулирам IF()
състояние математически. Това би било еднакво валидно:
RETURN DATE_ADD(p_date, INTERVAL p_weekday - WEEKDAY(p_date) + IF(p_weekday - WEEKDAY(p_date) < 0, 7, 0) DAY);
И в интерес на обективността, при изпълнение на 1 милион итерации няколко пъти на всяка функция IF
-базираната версия беше средно с около 4,2% по-бърза от ROUND
-базирана версия.