業務上よくあるシチュエーションとして 午前9時から18時までの毎時0分
や 平日の19時
みたいなスケジュールを組みたいことがある。
cronなんかだと 0 9-18 * * *
や 0 19 * * 1-5
のように書けば良いが、MySQLのイベントスケジューラの場合ではどう書くか。
サマリ
特定の時間帯のみや特定の曜日のみなどの複雑な条件は設定することができないため、スケジューラが実行する処理の中で時刻による実施要否判定を行う必要がある。以下のように書けばよい。
DELIMITER | CREATE EVENT {{イベント名}} ON SCHEDULE {{任意の定期実行スケジュール}} DO BEGIN SET @NOW = CURRENT_TIMESTAMP; IF {{時刻による判定}} THEN {{やりたいこと}}; END IF; END | DELIMITER ;
解説
MySQLのスケジューラ設定 CREATE EVENT ON SCHEDULE
は以下のパターンでしか設定できない。
- 特定の時間に単発実行 (AT [timestamp値])
- 一定の間隔で定期実行 (EVERY N [DAY|HOUR等])
- STARTS [timestamp値] と組み合わせて特定時刻の定期実行も可
午前9時から18時までの毎時0分に特定のストアドプロシージャを呼び出す
みたいなケースを考える。
まずスケジュールの記載。範囲指定はできないので毎時実行とする。
CREATE EVENT call_hogehoge_everyday_9to18 ON SCHEDULE EVERY 1 HOUR STARTS '2022-01-01 09:00:00' DO call hogehoge();
これだけだと毎時実行になってしまうので時刻判定ロジックを書いていくが、、、
- 現在時刻を任意の変数に入れて
- No.1の変数を時刻比較して範囲内であることをチェックする
- trueな場合に任意の処理を実行
としたいためイベント内で複数の処理を呼び出すことになるが、その場合は複合ステートメントを利用する。
ただし複数の処理を呼び出すために途中で ;
を入れてしまうとそこでクエリが切れてしまうため、 イベントを作成する前に DELIMITER
でデリミタを変更しイベント作成後に戻す必要がある。
DELIMITER | CREATE EVENT call_hogehoge_everyday_9to18 ON SCHEDULE EVERY 1 HOUR STARTS '2022-01-01 09:00:00' DO BEGIN call hogehoge(); END | DELIMITER ;
あとはここにIF文で時間帯判定を追加すれば良い。これで完成形。
DELIMITER | CREATE EVENT call_hogehoge_everyday_9to18 ON SCHEDULE EVERY 1 HOUR STARTS '2022-01-01 09:00:00' DO BEGIN SET @NOW = CURRENT_TIMESTAMP; IF time(@NOW) NOT BETWEEN hour('09:00:00') AND hour('18:00:00') THEN call hogehoge(); END IF; END | DELIMITER ;
平日だけやりたいならIF文の中を dayofweek(@NOW) IN (1,2,3,4,5)
とか書けばできる。