コラム コラム:一時領域(変数・ファイル)を活用

本記事では、タスクの作成時において、手間や複雑さを減らすための一時領域の活用法について紹介します。

まず、以下のような処理を考えるとします。
-----------------処理内容:ここから-----------------
■1. 下図のようなExcelから、「売り数」が「70」以上、または「売上高」が「30000」以上の商品をピックアップ

■2. 1の条件に合致する行の「商品名」「売り数」「売上高」をメール本文にのせて管理者にメール送信
なお、メールの冒頭には固定句をつける
-----------------処理内容:ここまで-----------------

サンプル用のExcelはこちらよりダウンロード可能です。

単純に考えると、以下のような流れの処理になりそうです。
A. Excelをデータセット化
B. Aのデータセットをループ
C. ループの中でIF分岐
D. IF条件に合致したらメール送信
(処理構築例)

<AMEXCEL ACTIVITY="get_cell" WORKBOOK="%GetDesktopDirectory()%\00009183_URIAGE_DATA.xlsx" SAVETYPE="do_not_save" ACTION="rangebyreference" RESULTDATASET="ds_uriage" STARTCELLREF="A2" LASTCELL="YES" />
<AMLOOP ACTIVITY="dataset" DATASET="ds_uriage" />
<AMIF EXPRESSION="%(ds_uriage.C &gt;= 70) OR (ds_uriage.D  &gt;= 30000)%" USECOMPLEXUI="YES" />
<AMEMAIL ACTIVITY="send" SERVER="SMTP.example.com" TLSCIPHERS="All" TLSVERSIONS="Any" FROM="from@example.com" TO="to@example.com" SUBJECT="売り上げ好調商品">今月の売り上げが好調な商品は以下です。

商品名.売り数,売上高
%ds_uriage.A%,%ds_uriage.C%,%ds_uriage.D%</AMEMAIL>
<AMIF ACTIVITY="end" />
<AMLOOP ACTIVITY="end" />

ところが、上記のような処理にすると、合致する行が存在する数だけ管理者あてにメールが送信されることになってしまいます。
今回はテストデータなので少ない件数ですが、仮に100件合致するとそれだけで100通のメールが送信されます。

一方で、実行するまでどの行が条件に合致するか分かりませんし、何行ヒットするのかも分からないので、下記のような設定の仕方は意味がありません。

そこで、「処理結果を一時的に保存・格納しておく領域」の必要性が出てきます。
以下のような性質があれば条件を満たすことが出来ます。
・ループが次の行に移っても記録したデータが揮発したり、上書きされたりしない
・後からデータが追記できる
・AutoMateのタスクの中でメールの本文などに利用可能
・タスクを実行するごとに作り直す(=クリアする)ことができ、前回の実行結果が残存したり、影響したりしない

以下の例では、それらの性質を満たすことのできるものとして、「ファイル」「変数」の2種を紹介します。

まずは、考え方がより単純な「ファイル」から解説します。

■1. ファイルを処理の一時領域として利用(以下では、テキストファイルを想定します)
まず利用できるものとして、テキストファイルが挙げられます。
テキストファイルであれば、Excelのように開くのに時間を要することなく、「ファイル システム - ファイルへの書込み」アクションで高速に記録できます。
方策としては・・・
1-1. メール送信アクションをループよりも後ろに外出し
1-2. IFの内部のアクションを「ファイル システム - ファイルへの書込み」アクションに変更、書込み先は一時ファイルを指定
1-3. 前に実行された同じタスクの実行結果が影響することを防ぐため、ループよりも前に該当の一時ファイルを削除するか、固定文句で上書き
1-4. メールを送信するアクションで、「ファイルのコンテンツを本文として使用する」にチェックを入れ、一時ファイルを指定
※別途変数を作成し、一時ファイルの内容を「ファイル システム - ファイルからの読込み」アクションで読み出す形でも問題ありません
(処理構築例)

<AMEXCEL ACTIVITY="get_cell" WORKBOOK="%GetDesktopDirectory()%\00009183_URIAGE_DATA.xlsx" SAVETYPE="do_not_save" ACTION="rangebyreference" RESULTDATASET="ds_uriage" STARTCELLREF="A2" LASTCELL="YES" />
<AMFILESYSTEM ACTIVITY="write_file" FILE="%GetDesktopDirectory()%\work.txt" APPEND="no">今月の売り上げが好調な商品は以下です。

商品名.売り数,売上高</AMFILESYSTEM>
<AMLOOP ACTIVITY="dataset" DATASET="ds_uriage" />
<AMIF EXPRESSION="%(ds_uriage.C &gt;= 70) OR (ds_uriage.D  &gt;= 30000)%" USECOMPLEXUI="YES" />
<AMFILESYSTEM ACTIVITY="write_file" FILE="%GetDesktopDirectory()%\work.txt">%ds_uriage.A%,%ds_uriage.C%,%ds_uriage.D%</AMFILESYSTEM>
<AMIF ACTIVITY="end" />
<AMLOOP ACTIVITY="end" />
<AMEMAIL ACTIVITY="send" SERVER="SMTP.example.com" TLSCIPHERS="All" TLSVERSIONS="Any" FROM="from@example.com" TO="to@example.com" SUBJECT="売り上げ好調商品" BODYFILE="%GetDesktopDirectory()%\work.txt" />

一方で、この処理のままだと、処理対象データがなかった場合もメールが送信されてしまうので、それを避ける場合は別途変数とロジックを追加します。
1-5. 対象行をカウントする為の変数を用意し、初期値を0にする
1-6. IFブロック内で1-5の変数を増加させるアクションを追加(=条件に合致したらカウントアップ)
1-7. 1-5の変数が0以外の場合のみメールを送信
(処理構築例)

<AMVARIABLE NAME="var_cnt" VALUE="0" DESCRIPTION="処理対象行カウント用変数" TYPE="number" />
<AMEXCEL ACTIVITY="get_cell" WORKBOOK="%GetDesktopDirectory()%\00009183_URIAGE_DATA.xlsx" SAVETYPE="do_not_save" ACTION="rangebyreference" RESULTDATASET="ds_uriage" STARTCELLREF="A2" LASTCELL="YES" />
<!--一時ファイルを固定文句で上書き-->
<AMFILESYSTEM ACTIVITY="write_file" FILE="%GetDesktopDirectory()%\work.txt" APPEND="no">今月の売り上げが好調な商品は以下です。

商品名.売り数,売上高</AMFILESYSTEM>
<!--データセットの行数分ループ-->
<AMLOOP ACTIVITY="dataset" DATASET="ds_uriage" />
<AMIF EXPRESSION="%(ds_uriage.C &gt;= 70) OR (ds_uriage.D  &gt;= 30000)%" USECOMPLEXUI="YES" />
<!--条件に合致した場合、該当行データをファイルに書き込み-->
<AMFILESYSTEM ACTIVITY="write_file" FILE="%GetDesktopDirectory()%\work.txt">%ds_uriage.A%,%ds_uriage.C%,%ds_uriage.D%</AMFILESYSTEM>
<!--条件に合致した行の数を + 1する-->
<AMVARIABLE ACTIVITY="increment" RESULTVARIABLE="var_cnt" />
<AMIF ACTIVITY="end" />
<AMLOOP ACTIVITY="end" />
<!--対象行が0行でない(=1行以上)ならば、一時ファイルを本文としてメール送信-->
<AMIF EXPRESSION="%var_cnt% &gt; 0" />
<AMEMAIL ACTIVITY="send" SERVER="SMTP.example.com" TLSCIPHERS="All" TLSVERSIONS="Any" FROM="from@example.com" TO="to@example.com" SUBJECT="売り上げ好調商品" BODYFILE="%GetDesktopDirectory()%\work.txt" />
<AMIF ACTIVITY="end" />

■2. 変数を処理の一時領域として利用
「変数」を利用する方法を後ろにもってきている理由としては、ファイルを使用する場合に対して
・以前のデータとの結合方法
・改行データの挿入の仕方
(今回は直接「変数 - セット」アクション内で改行していますが、「%」で囲まれた計算式内では改行を「vbCrLf」と表記する必要があります)
を考慮する必要があるためです。
一方で、それらを考慮した作りにすることでファイルを作成せずとも対応可能になります。
また、変数はファイルと違いタスクが終了すると揮発するので、ファイルを削除する等の手間は必要ありません。
(処理構築例)

<AMVARIABLE NAME="var_cnt" VALUE="0" DESCRIPTION="処理対象行カウント用変数" TYPE="number" />
<AMVARIABLE NAME="var_tmp" DESCRIPTION="メール本文用一時領域" TYPE="text">今月の売り上げが好調な商品は以下です。

商品名.売り数,売上高</AMVARIABLE>
<AMEXCEL ACTIVITY="get_cell" WORKBOOK="%GetDesktopDirectory()%\00009183_URIAGE_DATA.xlsx" SAVETYPE="do_not_save" ACTION="rangebyreference" RESULTDATASET="ds_uriage" STARTCELLREF="A2" LASTCELL="YES" />
<!--データセットの行数分ループ-->
<AMLOOP ACTIVITY="dataset" DATASET="ds_uriage" />
<AMIF EXPRESSION="%(ds_uriage.C &gt;= 70) OR (ds_uriage.D  &gt;= 30000)%" USECOMPLEXUI="YES" />
<!--条件に合致した場合、該当行データを変数に追記-->
<AMVARIABLE ACTIVITY="set" VARIABLENAME="var_tmp">%var_tmp%
%ds_uriage.A%,%ds_uriage.C%,%ds_uriage.D%</AMVARIABLE>
<!--条件に合致した行の数を + 1する-->
<AMVARIABLE ACTIVITY="increment" RESULTVARIABLE="var_cnt" />
<AMIF ACTIVITY="end" />
<AMLOOP ACTIVITY="end" />
<!--対象行が0行でない(=1行以上)ならば、一時ファイルを本文としてメール送信-->
<AMIF EXPRESSION="%var_cnt% &gt; 0" />
<AMEMAIL ACTIVITY="send" SERVER="SMTP.example.com" TLSCIPHERS="All" TLSVERSIONS="Any" FROM="from@example.com" TO="to@example.com" SUBJECT="売り上げ好調商品" BODYFILE="%GetDesktopDirectory()%\work.txt" />
<AMIF ACTIVITY="end" />

Excelの計算式において作業用の列を作成するのと同様に、AutoMateにおいても一時的に作業用の領域を作成した方が処理の構築が簡素化できる場合が多くあります。
変数や一時ファイルなどの領域を活用する場面があれば、参考にしてください。