Tips2. SYSDATEは使わない!

ロジック中にSYSDATEが使われてしまうケース

有効開始日と有効終了日という値で履歴管理されたテーブルから「現時点で有効なデータ」を抽出するとき

WHERE SYSDATE BETWEEN START_DATE AND END_DATE

と書いていないでしょうか。

「現時点」を表すのにSYSDATEを使うのは、特に間違っていないように思えますが、次の点についてもう一度考えてください。

  • 「現時点」は本当にSYSDATEで表される時分秒なのか。
  • そのロジックはどうやってテストするのか

ロジック中にSYSDATEが記述されていることの問題点

1点目についてよくあるのが業務システムにおける夜間バッチ処理です。

2018年1月31日の夜間に行われる一連の夜間バッチ処理が、夜の11時に開始されるとしましょう。終了するのは翌2月1日の午前4時です。
前述の条件では、夜中の0時を回った時点で、対象となるデータが変わります。
それは想定された動作でしょうか。
たいていの場合は、一連の夜間バッチ処理が終了した時点で2月1日に変わるのであって、それまでは1月31日として処理したいはずです。

2点目についても、大規模なシステムやプロジェクトであれば問題になります。

例えば、1年後の法改正に向けた新機能を追加しようとしている場合、ロジック中にSYSDATEが含まれていれば、その検証を行うためにはサーバの日時を変更しなければなりません。
OSに管理者権限でログインしてdateコマンドでシステム日時を変更するだけであれば、それほど大した作業ではないのかもしれませんが、まずサーバ管理者に新たな作業を増やすことになりますし、管理された開発環境であれば、システムログなどシステム日時による前後関係がわからなくなったり、場合によってはシステムに異常をきたすこともあり得ます。

回避方法

これらの問題を回避するためには、SYSDATEを使用せず、バッチ処理日付を別に保持し、それを取得するための共通関数を作成します。
その関数名が仮にbatch_proc_dateであれば、

 WHERE batch_proc_date BETWEEN START_DATE AND END_DATE

と記述することになります。

バッチ処理日付の具体的な保持方法は特に定められたものはありませんが、日付だけの列を持つシンプルなテーブルを用意し、そこからSQLでデータを取得するだけの共通関数を作成するだけで良いでしょう。
本当にSYSDATEを使用したい場合は、この共通関数をSYSDATEを戻すだけの内容に書き換えるだけで対応できます。

夜間バッチの冒頭、もしくは一番最後に、1日インクリメントする処理を動かすことを忘れてはいけません。

一方で、監査目的の「このデータがいつ更新されたか」といった情報を保持するためにSYSDATEを使用するのは問題ありません(そうしなければ要件を満たせられないはずです)。

2018-02-25Oracle,設計SYSDATE

Posted by tfurukaw