データマクロ

 データマクロは、テーブルにおいて行の追加や値の変更といった操作が行なわれたときに、自動的に実行される処理を設定するものです。入力規則プロパティによるチェックに比べても高度なデータの制約が可能になるほか、ログの取得などの動作を実現できます。
 Access2010より加わった機能で、これによりテーブル自体の持つ機能が強化されました。

 あえてテーブルに関する一連の説明の中にこの節を設けましたが、マクロという機能についての知識があった方が理解がはかどると思われます。

データマクロの役割

 テーブルにおける行の追加や削除、値の変更があったときに、自動的に処理を行わせることができます。
 メリットとしては、データの操作に対するチェックがより完全なものになることが挙げられます。フォームを使ってデータを操作させるようなシステムでは、フォーム上のイベントに対してコードを記述して入力された値が適切かチェックしたり、値を別のテーブルに転記したり、という仕組みが用いられることがあります。しかし、これらはテーブルを開いてデータを直接操作された場合には全く機能しません。データマクロによってこれらの動作を実現すれば、フォームでデータを操作しようがテーブルを直接操作しようが同じチェックが働きますので、抜け穴はなくなります。また、フォームが複数にわたる場合であってもそれぞれにチェックを設ける必要がなく、手間が省けます。
 また、積極的な用途としては非正規化のサポートが挙げられます。例えば販売明細テーブルに各商品の販売金額を記録する一方で、販売テーブルにその合計金額を記録することがあります(販売テーブルを参照するだけで集計できるようにするため)。この場合、両方のテーブルの金額は常に一致していなければなりませんが、データマクロを用いてチェック及び更新を行い整合を保つことができます。

データマクロの作成方法

f:id:accs2014:20170225120159p:plain:right:w400

 データマクロを作成するときは対象となるテーブルをデータシートビューで開き、テーブルタブを選択したうえでどのタイミングで処理を実行するかを選択します。
 また、デザインビューで開いたときもデザインタブを選択すると同じ選択肢が現れますのでここからデータマクロを設定することができます。


データマクロの設定例

 まずはデータマクロの実行のイメージをつかんでいただくため、簡単な設定例を紹介します。

レコードの更新時刻を特定の列に記録する

 設定例の一つとして、テーブルのデータに追加や変更があった際に、その追加や変更のあったレコード(行)の特定の列に、その時刻を記録する設定をしてみます(タイムスタンプ)。

f:id:accs2014:20160801230617p:plain:right:w400

 例としてこのようなテーブルを用いるものとし、行の追加や変更があった日時を「更新日時」列に記録するものとします。


f:id:accs2014:20170225120159p:plain:right:w400

 上記と同じ画像ですがデザインビューのデザインタブから「データマクロの作成」→「変更前」と選択します。


f:id:accs2014:20160801230619p:plain:right:w400

 設定用のウインドウが現れます。
 プルダウンにより実行する処理(アクションといいます)が選択できますので、ここで「フィールドの設定」を選択します。


f:id:accs2014:20160801233503p:plain:right:w400

 すると、設定しようとするフィールド(列)の名と設定値を聞かれますので、それぞれ「更新日時」、「Now()」と記入します。後者はシステムの時刻を表す関数です。
 記入が終わったら右上の方に見える赤い×マークをクリックして保存します。


f:id:accs2014:20160801230621p:plain:right:w400

 そしてテーブルに戻り「単価」列の値を変更して別の行に移るときに「更新日時」に日時が記録されます。
 当然ながら「商品名」などの列を変更しても日時が記録されます。また、「更新日時」列そのものを変更しようとしても直ちに現在の日時が上書きされますので、値を削除することはできません。


レコードの操作に関するログをシステムテーブルに記録する

 データマクロを利用して、レコードの追加、更新、削除を行ったタイミングでその詳細を記録することができます。ログの保存先はシステムが初めから用意しているログ記録用のテーブルとなります。
 似たような記録の方法として、長いテキスト型のフィールドに対するColumnHistory関数の利用(こちらで紹介しています)がありますが、データマクロを利用するとデータ型を気にせず、またさまざまな内容を記録することができ、より本格的なログの作成が可能です。

f:id:accs2014:20170223181052p:plain:right:w200

 やり方ですが、まずログの保存先となるテーブルを表示してみます。
 ナビゲーションウインドウ上で右クリックし、メニューから「ナビゲーションオプション」を選択します。


f:id:accs2014:20170223183500p:plain:right:w400

 ウインドウが現れますので、左下部にある「システム オブジェクトの表示」にチェックを入れ、「OK」をクリックします。


f:id:accs2014:20170223181050p:plain:right:w200

 するとナビゲーションウインドウ上に、システムにより作成されているテーブルが現れます。
 このうち、「USysApplicationLog」テーブルが、ログを記録するためのテーブルです。


f:id:accs2014:20170223200305p:plain:right:w400

 次の手順ですが、ここではレコードの更新時のログを記録することとします。そこで、デザインビューのデザインから「データマクロの作成」→「更新後処理」と選択します。
 (レコードの追加時にログを作成するのであれば「挿入後処理」を、削除時であれば「削除後処理」を選択します。)


f:id:accs2014:20170223181049p:plain:right:w400

 具体的な記録内容の設定を行います。ここでは、商品の単価変更があったときにその対象となった商品コード、商品名、変更の前後の単価、そして変更の日時を記録することとします。
 まず、アクションとして「If」を選択し、その右側に次のように入力します。

[単価]<>[Old].[単価] 

 これは、「変更後の単価([単価])が変更前の単価([Old].[単価])と異なるのであれば」という条件を意味します(ただし、変更前の値か変更後の値がNullであるときはこの条件は真とならず、ログが記録されません。これを避けたい場合は「単価」列の値要求プロパティの値を「はい」にするか、上記の式に手を加えるなどして判定の方法を工夫する必要があります。上記の式の代わりに「Updated("単価")」と入力するのも一つの方法です)。
 また、その直下のアクションとして「イベントのログ記録」を選択し、「説明」の右側に次のように入力します。

=[商品コード] & "," & [商品名] & "," & [Old].[単価] & "→" & [単価] & "," & Now()

 ここでは「=」を含めて入力しないと、式がそのままログになりますので要注意です。
 以上の設定により、商品の単価の変更があったときに、商品コードと商品名、そして旧単価と新単価、さらに変更した日時がログとして記録されます。


f:id:accs2014:20170223181047p:plain:right:w400

 あとは商品の単価が変更されるたびに、「USysApplicationLog」テーブルの「Description」列に、上記で設定したように商品コードと商品名、そして旧単価と新単価、変更した日時が記録されていきます。
 なお、「USysApplicationLog」テーブルには「イベントのログ記録」アクションによる説明内容のほか、下記の「エラーの生成」により発生したエラーの内容も記録されます。


アクション一覧

 データマクロで実行できるアクションは19種類あります。また、実行するタイミングによって可能なアクションは異なります。
 アクションの一覧と実行タイミングとの対応については以下の通りです。

挿入後
処理
更新後
処理
削除後
処理
削除前変更前
If
グループ化
コメント
イベントのログ記録
エラーの生成
エラー時
データマクロの実行
フィールドの設定
マクロエラーのクリア
マクロの中止
レコードごと
レコードごとに終了
レコードの作成
レコードの削除
レコードの参照
レコードの編集
ローカル変数の設定
全マクロの中止
電子メールの送信

If

 特定の条件を満たしたときにアクションを実行する、というときに使います。
 これを選んだら、「If」の文字の右側の欄に条件を記入し、その直後(「If文の最後」の文字より手前)に、実行しようとする別のアクションを設定します。アクションは複数盛り込むことができます。
 また、Else(If条件を満たさないとき)やElse If(If条件を満たさないとき、さらに別の条件を設定)を設定することも出来ます。

グループ化

 複数のアクションを1つにまとめて扱いたいときに使います。次の「コメント」と同様に、マクロの内容を理解しやすく、扱いやすくするための機能であり、直接的に動作するようなアクションではありません。
 これを選んだら、「グループ:」の右側の欄に説明を記入します。
 その直後(「グループの最後」の文字より手前)に、各種のアクションを設定していきます。

コメント

 注釈を記入するときに使います。
 ユーザーに対するメッセージボックスのようなものではなく、VBAでの「'」のように、あくまで単なるメモとして機能します。

イベントのログ記録

 上記の設定例で示しているように、システムオブジェクトである「USysApplicationLog」テーブルに操作のログを記録することができます。
 ログとして記録する内容は「説明」欄に記入しますが、単に文字列だけでなく、その時々にフィールドに記録された値を記録することもできます。例えば説明欄に「=[単価]」と入力すれば変更後の「単価」列の値を、「=[Old].[単価]」とすれば変更前の「単価」列の値を記録できます。関数を用いることも可能です。

エラーの生成

 このアクションが実行された時点でマクロの実行は中断されます。また、「変更前」「削除前」においてこのアクションが実行された場合、テーブルに対する操作(レコードの追加、変更、削除)も完了できなくなりますので、このアクションを置くだけでデータの操作を阻止することができます。
 ただし、次の「エラー時」による設定を別途行うことで、エラー生成後もマクロを実行し、テーブルに対する操作を続行させることも出来ます。
 「エラー番号」欄と「説明」欄により、任意のエラー番号とエラーの説明を設定することができます。「変更前」「削除前」におけるエラー生成時には「説明」欄の内容がメッセージとして表示されます。

エラー時

データマクロの実行

フィールドの設定

 
 上記の設定例で示しているように、指定した列(フィールド)に値を設定(記録)することができます。このアクションは「変更前」でしか使用できず、対象となる行(レコード)は、変更されようとしているレコードのみです。値の変更に伴い他のレコードの値を変更しようとするときは、「更新後処理」で「レコードの編集」アクションを用いることとなります。
 設定の仕方ですが、「名前」欄に設定しようとするフィールドの名前を入力し、「値」欄に記録しようとする値を入力します。関数を用いることもできます。

マクロエラーのクリア

マクロの中止

 このアクションが実行された時点でマクロの実行は終了します。この後にアクションがあっても実行されません。通常はIfアクションと共に用いられます。
 エラーの生成と違い、テーブルに対する操作(レコードの追加、変更、削除)は常に問題なく完了します。

レコードごと

 テーブルまたはクエリを指定し、条件で絞り込んだレコード(全レコードも可)に対し、アクションを設定し操作を行うことができます。
 Ifと同様に複数のアクションを盛り込むことができます。

レコードごとに終了

 「レコードごと」による操作を途中で終了することができます。

レコードの作成

レコードの削除

 レコードを削除します。例えば「レコードごと」の中に含めれば、一定の条件を満たすレコードを全て削除することができます。

レコードの参照

レコードの編集

 指定したフィールドの値を、指定した値に書き換えることができます。

ローカル変数の設定

全マクロの中止

電子メールの送信

 メーラーにより電子メールが送信されます。
 宛先、CC、BCC、件名、本文が設定できます。「=」から始まる式を入力することで、フィールドの値や関数の値を利用することもできます。
 管理者の環境(Office365デフォルト)ですと、マクロ動作時に送信の許可/拒否の選択画面が表示され、許可した場合でもメールはOutlookの送信トレーに留まります。実際に送信されるのは、その後にOutlookを開いた時となります。
 いかにも通報用といった感じですけども、バックグラウンドで機能させたい場合は設定の変更が必要になりますし(試してませんが)、セキュリティの確保に注意が必要です。

備考

 データマクロを用いても、主キーやインデックスの制約に反するような値の変更はできません。例えば主キーである列については値をNullにはできません。
 また、データマクロによるデータの操作によって、別のデータマクロ(あるいは元のデータマクロそのもの)が作動します。これにより、例えば更新後処理として同一のテーブルの内容をさらに更新するようなデータマクロを作成すると、無限ループに陥ることがあります。ただし、Accessはこれを検知して停止しますので、こうしたデータマクロは全く動作しないか、あるいは不完全に動作して終了します。
 なお、こうした各種のエラーが発生してもメッセージは表示されないものの、上記のUSysApplicationLogテーブルにエラー内容が記録されますので、参考とすることができます。