第6章
リレーションからコンテキストへ

最終更新日:


6-2コンテキストが絡むデータベース

FileMakerではコンテキストの考え方をどうしても考慮しないと行けない場面が出てきます。このとき、リレーショナルデータベースの設計で使われるER図から考え方を変えてリレーションシップのグラフを作る必要が出てきます。ここでは、コンテキストごとにリレーションを別々に作るという考え方で、設計を複雑にならないようにするということを説明します。

リレーションシップでのコンテキスト

書籍の中では、一般的な伝票作成のアプリケーションを紹介しましたが、伝票と明細、そして商品マスターがあるというテーブル定義を行い、それらをキーフィールドのidと外部キーフィールドで結びつけているということを説明しました。

ここまではシンプルなリレーショナルデータベースでしたが、さらに、応用例として、商品を選択するときにカテゴリを選んで、さらにそのカテゴリに含まれる商品を選択する方法を説明しましたが、そこでは汎用的に、1つの商品が複数のカテゴリに含まれる場合まで実現をしました。そのため、単に商品マスターにカテゴリを記録する方法だと、多対多のリレーションになるため、中間に対応表となるテーブルをはさんで、1対多のリレーションにまとめたわけです。

このとき、「どのカテゴリに絞り込んだのか」という情報は、グローバルフィールドに記録しました。明細では、どのカテゴリに絞り込んだのかは記録不要としたからです。どの商品を選んだのかということを記録しておけばいいのであれば、カテゴリまでは通常は記録しないと思われます。ただし、明細のテーブルにあるレコードの処理でカテゴリを選択したので、そのグローバルフィールド「商品カテゴリid」は、「明細」テーブルに定義を行いました。そのときの、リレーションシップのグラフを改めて示しておきます。

5章までのリレーションシップ

ここでまず、注目したいのは、「伝票が作成できる」という視点で見ると、すべてのテーブルは必要ないということです。伝票が作成できるには、「伝票」「明細」「商品」の3つのリレーションが必要ですが、後はなくてもかまいません。

一方、「カテゴリを選択しそのカテゴリに所属する商品だけをリストアップして選択したい」というユーザインタフェースの要件を満たすのは、「明細」「商品分類」「商品カテゴリ選択」の3つのリレーションということになります。つまり、「明細」の「商品カテゴリid」フィールドで指定した値により、「商品分類」のテーブルのレコードが絞り込まれることで、指定したカテゴリに絞り込まれたレコードのセットが得られ、これを値一覧で使うということをやったわけです。

ここでは前者の「伝票作成」と後者の「カテゴリによる絞り込み」という2つの作業が、たまたま、同じ「明細」テーブルを使っていることもあって、1つの「明細」テーブルをベースにそれぞれのリレーションを定義しました。

しかしながら、前者は「明細」テーブルはまさに伝票の明細を記録するために使っているのに対し、後者の場合は「明細」テーブルは「どのカテゴリを選んだか」を記録するためだけに使っています。つまり、同じ「明細」テーブルでも使い方が異なっているとも言えますし、注目しているデータが違うとも言えます。こうした状況は、それぞれが「違うコンテキストである」と表現することになります。

もっとも、後者の利用であえて「明細」テーブルである必要はないとも言えるのですが、その点は少し目をつむってください。

コンテキストごとに分類する

ER図はエンティティ同士の関連性を定義するので、ここでのリレーションシップのグラフのように記述します。しかしながら、FileMakerでは、コンテキストごとにリレーションを定義するということができます。

前の図でのリレーションシップにおいて、左下にある「テーブルの追加」ボタンをクリックし、新たにテーブル定義の「明細」をもとにしたテーブルを作ります。ここでは「商品選択_明細」というテーブル名にします。

テーブル定義の「明細」をもとにテーブルを作成

新たに「商品選択_明細」テーブルが作成されます。そして、「明細」と「商品分類」を結んでいるリレーションを選択してDeleteキーを押すなどして、リレーションを削除します。そして、改めて、「商品分類」テーブルの「カテゴリid」と、「商品選択_明細」テーブルの「商品カテゴリid」をドラッグしてリレーションを定義します。

、「商品分類」と、「商品選択_明細」とのリレーションを定義

このように、伝票作成と、カテゴリからの商品選択に、リレーションを分離しました。ただ、ここで、新しく作ったテーブルを実際に使用するように、ほかの部分の設定を変更しなければなりません。商品を一覧するための値一覧として「商品一覧」を作成していました。この設定を変更します。値一覧の定義ダイアログボックスで「商品一覧」を選択して、「編集」ボタンをクリックし、そして、「フィールドの指定」ボタンをクリックしてフィールド指定を変更します。フィールド指定では「商品カテゴリ選択」テーブルを使うのはそのままですが、「関連レコードの値のみを含める」を選択しており、その下の「次のテーブルから」では、新しく作ったテーブル「商品選択_明細」を選択します。以前選択していた「伝票」は関連テーブル、つまりリレーションで結合のあるテーブルではなくなったので、ここでは指定できなくなります。ここで改めて「商品選択_明細」を選ぶことは手作業で行う必要があります。

「商品選択_明細」を選択する

本書の伝票のサンプルでは、これだけの変更で、従来通りに機能するはずです。名西行にある「商品カテゴリid」のポップアップメニューでカテゴリを選択し、「商品id」のポップアップメニューでは選択したカテゴリに応じてリストされる項目が絞り込まれています。

同じようにカテゴリ選択ができる

ここで、1つのレイアウトで、異なるリレーションの結合がどう関連づけられているのかということになりますが、改めて、明細にある「商品id」フィールドの設定をみてみましょう。ここの設定は、この例では変更しないでもかまいません。もちろん、「明細」テーブルの「商品id」フィールドのデータを表示するという手設定になっていますが、ここでのポップアップメニューのもとになっているのは「商品一覧」という値一覧です。値一覧は違うリレーションではありますが、そちらのリレーションで得られる商品一覧は、それはそれで独自に構築することで問題はないはずです。「商品カテゴリid」が決められていれば、それに従った商品の一覧が作られるということです。

「商品id」のポップアップは「商品一覧」という値一覧から構成する

リレーションシップを分ける理由

こうしてリレーションシップの図で、用途ごとにテーブル間のリレーション結合を分離させるということができることがわかりました。海外のドキュメントでは、こうして分離したそれぞれのテーブルのグループを、TOG(Table Occurrence Group)という言い方をしていますが、これは、FileMaker用語ではなく通称です。ここでは「テーブルのグループ」と呼ぶことにします。テーブルのグループは、多くの場合「1つの用途を持つ」という特徴があります。もちろん、工夫をすれば、複数の用途に使えますが、あえて、異なる用途に使い回すよりも、用途ごとに異なるグループを定義する方がFileMakerでは見通しがよくなります。次のような例で説明しましょう。

伝票のデータベースで、商品ごとの合計売上金額を計算することを考えます。もちろん、レイアウトで計算する方法もありますが、ここでは、テーブル定義に計算フィールドを追加する場合を考えてみます。「商品」のテーブルと「明細」のテーブルは関連づけられているので、商品ごとに「明細」の金額のフィールドを合計すればいいわけです。

もちろん、テーブル定義の「商品」を、データベース定義のダイアログボックスの「フィールド」のタブで呼び出します。そして、計算フィールドを作成しますが、ここではもちろん、計算式を指定しなければなりません。何気なく作業をしていると気づかないのですが、この計算式を指定するダイアログボックスのいちばん上には、「次のコンテキストからこの計算式を評価する」というドロップダウンリストがあります。そして、ここには「商品」というテーブル定義から作られた2つのテーブル「商品」と「商品カテゴリ選択」が見えています。ここでの選択を行わないといけません。つまり、どのテーブルをもとにして計算するのかを指定しますが、言い換えれば、そのテーブルからのリレーション、つまりはどのテーブルのグループを使うのかという指定にもなります。

評価するコンテキストとしてテーブルを選択する

ここでは伝票を形成しているリレーションのグループに属する「商品」テーブルを選択します。すると、ダイアログボックス左側のフィールド選択のリストの上にあるドロップダウンリストでは、「商品」テーブルが所属するグループのテーブルが「関連テーブル」としてリストアップされています。ここでは、「明細」テーブルの「金額」を指定し、Sum関数の引数に「金額」フィールドを指定することで、商品ごとの売上合計を求めることができます。

フィールド選択の部分では「関連テーブル」として分類されている
「明細」の「金額」を合計する式を設定した

「商品」レイアウトに、ここで定義した計算フィールドの「売上合計」を配置します。レイアウトは適当に整えました。そしてブラウズモードで表示すると、ともかく正しく計算されているように見えます。こうした計算式の指定は以前からFileMakerの基本技ではありますが、「次のコンテキストからこの計算式を評価する」というドロップダウンリストはFileMeker 7から追加されています。

計算フィールド「売上合計」をレイアウトに追加する
商品ごとの売上合計が正しく計算されている模様

では、ここであえて、「次のコンテキストからこの計算式を評価する」というドロップダウンリストで、別のテーブル「商品カテゴリ選択」を選んでみます。操作の上ではこちらを選ぶことも可能です。このとき、計算式の指定のダイアログボックスの左側にあるフィールド選択の部分では「商品カテゴリ選択」テーブルと同じグループのテーブルが「関連テーブル」となっています。なので、そこにあるテーブル定義の「明細」から作られている「商品選択_明細」テーブルを指定して、「金額」フィールドを指定し、「Sum( 商品選択_明細::金額 )」という式を設定します。そして、レイアウトを表示するのですが、どの商品も同じ金額を表示しており明らかに正しい結果になっていません。

コンテキスととして「商品カテゴリ選択」を指定した
売上金額はみんな同じというのは明白におかしい

もとの「商品」テーブルが含まれるテーブルのグループでは、「商品」と「明細」は1対多の関係になっていて、その「多」はまさに実際に売上があったデータそのものです。

一方、「商品カテゴリ選択」テーブルのグループでは、1つの商品に対して「商品選択_明細」は1つのレコードしか参照していません。こちらのグループは、あくまで商品をカテゴリで絞り込むという用途のものであって、「商品カテゴリ選択」テーブルの1レコードから、その商品の実際の売上データにはつながっていないのです。

前者のグループと後者のグループは、データの結びつきが違うのです。つまり、状況が違うという意味合いを込めて「コンテキストが異なる」と表現できる訳です。

(コラム)計算式で参照できるのは関連テーブルのみ

計算フィールドの計算式では、他のテーブルのフィールドも指定できますが、その場合関連テーブルのフィールドないしはグローバルフィールドでなければなりません。関連していないテーブルのフィールドを計算式に指定すると、OKボタンをクリックして確定しようとするときに、警告が出て式を修正しないといけなくなります。

関連していないテーブルのフィールドは参照できない(グローバルフィールドは例外)

テーブルのネーミング

用途ごとにテーブルのグループを分けるということを行うとすると、たとえば、図のようなリレーションシップになるでしょう。左上の部分は、通常の伝票作成のためのテーブルのグループです。そして、上の右は、伝票作成時に、カテゴリに応じて商品一覧を絞り込むためのグループです。そして、「カテゴリ」テーブルだけのものは、カテゴリ選択のための値一覧で使うテーブルです。中央は、特にレイアウトは作っていませんが、売上を期間で検索するためのテーブルのグループを別に作ってみました。そして、いちばん下は、商品マスターの入力時に、カテゴリを追加できるようにすることを想定したものです。

さらに用途ごとにテーブルのグループを作成した例

こうした方針でリレーションシップを作っていくと、同一のテーブル定義をもとにしたテーブルがたくさん作られます。何も考えずに作ると、「商品」「商品2」「商品3」のようにテーブル名が作られていってしまい、これは実は後から大変な苦労を強いられることになります。できれば、作ったテーブルが何の用途なのかをある程度分かるような名前、つまりは「グループ名」のようなものを作り、そのグループ名と、テーブル定義の名前を組み合わせたテーブル名にするのが、1つの解決策ではないかと考えます。もちろん、そうすれでなければ機能しないという訳ではありませんが、一つの指針としては合理的です。その場合「グループ名+テーブル定義名」にするのか、「テーブル定義名+グループ名」にするのかは好みもあるかもしれませんが、ここでは前者の方法で名前を付けてみました。グループ名とテーブル定義名の区切りは半角のアンダーラインにました。

たとえば、右上のカテゴリ選択のためのグループは、「商品選択」というグループ名として、それにテーブル定義名を加えた「商品選択_明細」「商品選択_商品分類」「商品選択_商品」の3つの名前を付けてみました。左上の伝票入力以外のテーブルはこの方法で名前を付けています。もちろん、名前は後から付け替えるのは簡単なので、自分で作ったデータベースの場合であれば、後から整理のために名前を付け替えるのはいいことでしょう。

たとえば、新規レイアウトを作るときの最初のダイアログボックスでは、「レコードを表示」のドロップダウンリストでテーブルを選択します。ここでは、テーブルは分類されないで単に名前でソートされて一覧されます。こうした場面では統一的なネーミングをしていないと選択を迷うだけでなく、間違える元になります。

テーブルが分類されない場合

一方、一度テーブルが指定された後でのさらにテーブルを選択するような場面では、非関連テーブルと関連テーブルで分類されます。図は、ポータルにフィールドを追加する場合ですが、ここではポータルなので関連テーブルのフィールドしか追加できません。ここではテーブルが絞り込まれているので、きちんとリレーションシップが作られていれば、それほどネーミングが問題にはならないかもしれません。

テーブルが関連テーブルと非関連テーブルに分類される場合

こうしてグループを分けておき、たとえば商品のマスター編集のためのレイアウトを作る場合は、「商品マスター_商品」テーブルを利用するレイアウトを作ります。そして、そのレイアウトにポータルを配置し、ポータルは「商品マスター_商品分類」テーブルに関連づけます。リレーションシップでの「商品マスター_商品」と「商品マスター_商品分類」テーブルの間のリレーションでは、「商品マスター_商品分類」テーブル側にリレーションを利用してのレコード作成や削除の許可を行っておきます。そして、ポータルには「商品マスター_商品分類」テーブルの「カテゴリid」フィールドと、「商品マスター_カテゴリ」テーブルの「カテゴリ名」フィールドを配置します。「カテゴリid」フィールドは、ポップアップメニューで、「カテゴリ一覧」の値一覧を使うようにしておきます。

「商品マスター」グループを使った商品管理のレイアウト
商品ごとに、カテゴリを選択し追加することができる

このレイアウトは、「商品選択」のグループに「カテゴリ」テーブル定義をもとにしたテーブルを結合させることで作成可能ではあります。しかしながら、「カテゴリで絞り込む」という用途と、「商品マスター管理」というまた別の用途で使うということを考えれば、異なるテーブルのグループで定義する方が、よりすっきりするということにもなります。

また、別々にした方が、本来関連性がないようなテーブル間のグルーピングが設定の上では可能になってしまいます。これは、間違ったレイアウト設計につながる落とし穴にもなるわけで、その意味では複雑になる場合には必ずグループごとに分けるということが、効率的な開発につながるといえるでしょう。