前回に引き続いて、「バーチャルリストで目次を生成する」が参照していた、バーチャルリストによるレポート生成の詳細を解説するシリーズの後半をご紹介します。
Virtual List Reporting, part 2
(元記事はこちら)
Kevin Frank
2016/6/26
バーチャルリストによるレポート生成方法を掘り下げるシリーズの後編にようこそ。
デモファイル: VLR-part-2.zip
繰り返しを避けるために、この記事では読者がパート 1で紹介した考え方と手法を理解しているものとして説明を進めます。(理解してない場合、この後の内容の一部はわけのわからない文章に感じるかもしれません。)ここで前回の復習として、簡単にVLRの利点をあげます。
- 柔軟性の高いフレームワークで、複雑なレポート生成の課題に対応
- 高速に動作(今回のデモではMulti-Findの手法を使用)
- テーブル定義やリレーションシップグラフの変更は不要
- 従来のFileMakerのレポート生成とは異なり、非関連の複数のテーブルから簡単にデータを結合可能(パート1のレポート6で紹介)
- 条件によっては、VLRによる開発は従来方式のFileMakerのレポート処理よりも格段に速い(パート1のレポート3で紹介)
このレポート作成のアプローチは、データの出来上がりの形があらかじめわかっている場合に適しています。これは、最終形が決まっていないレポート生成の課題にはVLRが使えないと言っているわけではありませんが、今回レポートを作成する販売データでは、3つのタイプと5つの地域というように、明確に区分が決まっています。
各レポートはそれぞれ専用のスクリプトで生成されていて自己完結型で、読みやすさと簡潔さの適度なバランスを取るようにしています。
パート1では最初の6つのレポートについて見てきました。今回はレポート7から始めますが、これは以下に示すようにレポート1の拡張版です。
レポート7
The difficult I’ll do right now
(困難なことは、すぐにやる)
The impossible will take a little while
(不可能なことは、少し時間がかかる)
— from “Crazy He Calls Me” by Sigman & Russell, 1949
VLRの利点のひとつは、「不可能な」レポート作成のリクエストにも対応できる便利なフレームワークであるという点です。たとえば、パート1内のすべてのレポートは、タイプ・年・月の様々な組み合わせに焦点を当てていて、地域については完全に無視していたことに気がついたでしょうか?
もちろん、レポート1のスクリプトとレイアウトを複製して、上の図のタイプ別レポートの枠を利用して地域に基づいたクロス集計レポートをシンプルに生成するという方法も可能です。しかし、依頼者が地域別レポートとタイプ別レポートを同じページに表示したいと言ったらどうすればいいでしょうか? あなたの最初の反応が「FileMakerでのレポート作成ではそれはできません」だとしたら、それを口には出さないでください。なぜなら、VLRを使えばこの種のことはいとも簡単にできてしまうからです。
レポート7のスクリプト戦略:
- まずレポート1のスクリプトとレイアウトをコピーする
- スクリプトの主要部分を複製し、二つの同一の部品を用意する
- パートAは、地域別の部分を生成する
- パートBは、タイプ別のセグメントを生成する
- 必要に応じて微調整をおこなう
アドバイス1:レポートを生成する前に以下のリンクをクリックしてください。
それによってレポートの生成中に裏で何が起こっているかを確認できます。
アドバイス2:レポート生成スクリプトは一時停止の状態で終了するので、その間にデータビューアか上の図のウインドウで$ローカル変数の内容を確認してください。「Continue(続行)」ボタンを押すという一手間が増えたのは、私が$$グローバル変数ではなく$ローカル変数を採用した結果です。
以下はレポートをレイアウトモードで表示しています。繰り返しの100と、103から107をラベル用に使用し、タイプ別のセクションで6,7列目を表示させないよう「オブジェクトを非表示にする」を設定しています。
ボディの上下の小計パートは、どちらもvirtual_num_1をソート対象に指定しています。
ここで少し解説が必要でしょう。レポートが地域とタイプを別々に集計するように、レポート生成スクリプトで地域のエントリには$sortCodeに1を設定しています。
そしてタイプのエントリには2を設定し、どちらもその$sortCodeを$col_101[$counter]に設定しています。
レポート上では$col_101[$counter]はcell_num_r[101]を介して表示されます。このフィールドの101番目の繰り返しの値でソートができれば便利ですが、残念ながらFileMakerの機能として、繰り返しが設定されているフィールドは[1]でしかソートをすることができません。 その対策として、非繰り返しの「バーチャル」フィールドを利用します。これは非保存の計算フィールドで、結果はテキストか、今回の場合は数字にします。
最後にレポート生成スクリプトは$vNum1に値を設定し、以下のように対応するバーチャルフィールドに基づいてソートを行います。
想定質問:ややこしい$sortCodeの関連をすべてなくして、その代わりに$vText1を$col_100[$counter]に設定して、virtual_text_1で降順に(依頼者は地域、タイプの順で表示させたいので)ソートしてはどうですか?
回答:はい、それでもうまくいきます。しかし$sortCodeはさらに拡張が可能で、VLRを目の前の課題の解決のためだけに使うのではなく、汎用性を持たせることができます。
レポート8
引き続き、前のレポートに改良を加えて次の課題を解決していくスタイルを進めて行きます。レポート8はレポート2の改良版になります。レポート2は以下のようにsalesを年・月でクロス集計しています。
レポート8では、ドリルダウンして地域ごとに小計を計算します。そしてその後ろに続けて全地域の合計(レポート2と同じ)を表示します。合わせると5つの地域と1つの全体合計をページあたり2つ表示できるので、レポートは3ページにわたり、以下のようになります。
レポートは、以下のように3つのレベルのネストされたループによって生成されます。
- 外側のループ:地域(ただし最後の繰り返しは全地域の合計)
- 2番目のループ:年
- もっとも内側のループ:月
レポート2と同じように、このレポートはカスタム用紙サイズのトリックを使ってレポートのレイアウトの横幅を1インチ余分に稼いでいます。(そのため、印刷をしたい場合はまずPDFを生成してからそのPDFを印刷してください。あるいはもし8.5″ x 12″の用紙が手元にあるのなら、FileMakerから直接印刷することも可能です。)
以下はレイアウトモードでの表示です。
レポート7で用いた方法で小計をしています。
レポート9
ここでの課題はデータを地域・年・タイプで分析し、その後で全地域を合わせて集計します。それを以下の形式で1ページに収めます。
私が簡単な方法としてデータをポータルで表示したと考えた方は…正解です。レイアウトモードで表示するとこうなります。(印刷出力したものにcell_num_rフィールドの繰り返し番号を手書きで示しています。)
このレポートのレイアウトは、virtual_parentという新しいテーブル上に設定されています。(ここでも「必要な分よりも多めのレコード」を持つようにします。私は任意で100レコード作成しました。)
フィールドは2つです。
以下のようにvirtual_listとのリレーションを設定します。
IDはvirtual_listテーブルで唯一の索引が設定されたフィールドであり、それを子側のリレーションとして利用します。親側のid_virtualは非保存の計算フィールドで結果はテキストに設定されています。その中身は複数行のキー(外部キーのリスト)になります。グローバル変数$$vMLK[繰り返し]に基づいて、レポート生成スクリプトによって値が設定されます。
この手法は1ページだけのレポートには大げさに感じるかもしれませんが、次のレポート10ではより意味を持ってきます。この枠組みが、目の前のレポート作成の要求に対応するためだけでなく、何が来るかわからない将来の要求にも対応するためだと考えれば、その意義が理解できるでしょう。
レポート9のスクリプト戦略:
- 外側のループは年ごとに繰り返す
(virtual_listのレコード行に対応) - 内側のループは地域+タイプの組み合わせごとに繰り返す
(virtual_listの列に対応) - 存在する$ローカル変数[繰り返し]を集計して年の合計の列に入れる
- $vMLK[1]に値を設定し、id_virtualに複数行キーを入れる
- レポート9のレイアウト(virtual_parentに基づく)に切り替え、1番目のレコードのみを対象にして、プレビューを表示
レポート10
次の要求は、順番に従ってさらに深く掘り下げ、年・地域・月で集計し、年ごとに改ページをします。(年がvirtual_parentの1レコードに対応します。)
各列の下の合計欄は、関連の集計フィールド[繰り返し]で、それぞれ集計する列に対応します。例えば、North地域でのWalk-In(店頭)の列(virtual_list::cell_num_r[3])はvirtual_list::zz_s_cell_num_r[3]に集計されます。
この巨大な集計作業の結果をvirtual_listのテーブルビューで見ると以下のようになります。
レポート9のスクリプトとレイアウトをできるだけ再利用するために、年を繰り返しの1番目に残すことにして、任意で51番目に3文字の月名を入れました。上のスクリーンショットでは見やすさのためにそれを繰り返しの1と2の間に置きました。
レポート10のスクリプト戦略:
- 外側のループは年+月の組み合わせごとに繰り返す
(virtual_listのレコード行に対応) - 内側のループは地域+タイプの組み合わせごとに繰り返す
(virtual_listの列に対応) - 年の合計の列に、存在する$ローカル変数[繰り返し]を集計した値を入れる
- $vMLK[1]に値を設定し、id_virtualに各レポートページに関連づく複数行キーを入れる
- レポート10のレイアウト(virtual_parentに基づく)に切り替え、必要な数のレコードのみを対象にして、プレビューを表示
$vMLKの処理の部分を解説すると、各年はvirtual_parentの1レコードに対応するので、あなたがこの記事を2016年に読んでいるのであれば、2009年から2016年に対応する8レコード(つまり8ページのレポート)があることになります。
親テーブルの1レコードごとに、以下のハイライトした行が..
..12個の項目からなるIDのリストを組み立てます。これはvirtual_listの関連する子レコード、つまりその年の月ごとのレコードに対応します。データビューアで表示するとこうなります。
ここで注意が必要なのは、各値の間にあるスペースは実際には改行です。$vMLK[8]のポップアップヘルプでそれがわかります。データビューアは(今回だけは皮肉でなく)便利にデータを横に表示します。
まとめ
パート1でも述べましたが、ここで再度繰り返します。
通常であれば複数の補助的なフィールドやリレーションシップを追加で作成しなければいけないところを、VLRを使うことによって、テーブル定義を触ったりリレーションシップグラフに変更を加えることを一切せずに、レポートを生成できるようになります。
関連するポイントとして、前回は明示的には言いませんでしたが、マルチユーザ環境で稼働中のシステム上で複雑なレポートを作成しなくてはいけないという場合に、この手法はとても安全です。(なぜなら、最初にテーブルとフィールドが設定された後は、テーブル定義をロックすることがないからです。)
このような状況が当てはまるかどうかに関わらず、VLRでは最初のセットアップが一度終われば、すべての力仕事はスクリプトとレイアウトのレベルでおこなわれ、レポート生成はプレゼンテーション層のみで実行されることになります。少し時間をかけてこの考え方に慣れてしまえば、単純なものを除いたほとんどのレポート生成で頼れる手法になるでしょう。