さらに別のアプローチで帽子をリングに投げ込みます:
編集: 問題のOracle関数が2番目の引数として文字列を受け取るので、これは要件に正確に適合しないことに少し遅れて気づきました。ただし、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
を掛けます。 (1週間の日数)
したがって、p_weekday
今週にすでに発生している場合は、オフセットp_weekday - WEEKDAY(p_date)
に7が追加されます。 、そのオフセットは負の数になり、将来の日付が必要になるためです。
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);
そして、客観性のために、各関数の1M回の反復を数回実行する場合、IF
ベースのバージョンは、ROUND
よりも平均して約4.2%高速でした ベースのバージョン。