楽しみにしていたTips ‘n’ Tricks, part 2がFileMakerHacksで公開されましたのでご紹介します。
Tips ’n’ Tricks(パート2)
(元記事はこちら)
Kevin Frank
2015/12/28
デベロッパーの道具箱の中身を紹介するTips ‘n’ Tricksのパート2にようこそ。今日紹介するものの中にはパート1の内容を前提にしているものがいくつかあります。もしまだ見ていないのであれば、そちらをチェックしてから続きを読むことをお勧めします。
まず最初は、ExecuteSQLのチップスを2つ紹介します。
Tip #1: COALESCEを知る
SQLのCOALESCE関数は、複数の引数をとり、ヌルでない最初の結果を返します。
COALESCE ( arg1 ; arg2 [; arg3 ; etc.] )
たとえば、以下の内容の顧客情報テーブルがあります。
ここで、Maryland州Bel Airに住む顧客について、customer name | address | city | state | zipの項目を持ったリストをテキスト形式で作成するよう依頼を受けました。ただしcustomer nameの列には、 Company nameがあればそれを、なければ代わりにFirst nameとLast nameを挿入します。
Diana Reeves | 336 S Main St | Bel Air | MD | 21014 I O Interconnect | 214 Fulford Ave | Bel Air | MD | 21014 Production Specialties | 418 S Main St | Bel Air | MD | 21014 Felipe Sanchez | 26 S Main St | Bel Air | MD | 21014
もちろんSQLを使わないFileMaker流のアプローチもいくつかあります。ですが実装の手軽さという点ではこの方法がもっとも簡単ではないでしょうか。
ExecuteSQL ( " SELECT COALESCE ( Company, FirstName+' '+LastName ), Address, City, State, Zip FROM Customers WHERE City = ? AND State = ? " ; " | " ; "" ; "Bel Air"; "MD" )
Tip #2: FM/SQLの日付データ再考
パート1で紹介したとおり、日付データはSELECT文では以下の形式で返されます。
YYYY-MM-DD
このデータをSQLの世界の中で引き続き操作するのであれば問題ないのですが、FileMakerにはこのままでは理解できません。前回お勧めしたのは、日付を簡単なSUBSTITUTE関数で日本の日付形式 (YYYY+MM+DD) に変換するという方法でした。その後Radu-Dan Sabauさんからのコメントで、COALESCE関数を使ってFileMakerが理解できる形式に強制的に変換する方法を紹介いただきました。
たとえば、次のような内容のLedger(台帳)テーブルにおいて、
以下の式を実行すると、
ExecuteSQL ( " SELECT \"date\" FROM Ledger WHERE idStudent = ? " ; "" ; "" ; "S00177" )
以下が返されます。
2015-10-06 2015-10-13 2015-11-05 2015-11-10 2015-12-01
しかし、クエリ式を以下のようにすると、
ExecuteSQL ( " SELECT Coalesce ( \"date\", '' ) FROM Ledger WHERE idStudent = ? " ; "" ; "" ; "S00177" )
結果は次のようになります。
10/6/2015 10/13/2015 11/5/2015 11/10/2015 12/1/2015
注1: COALESCE句の2つ目の引数は、シングルクオートのペアです。
注2: 「date」はSQLの予約後なのでエスケープ処理(ダブルクオーテーションの前のバックスラッシュ)が必要です。(フィールド名をエスケープ処理しなくてはいけないかどうかを気にしたり、フィールド名を決め打ちすることによってメンテナンス性が悪くなるのを避けたければ、過去の私の記事「ExecuteSQL: Robust Coding」を参照してください。)
次の2つは、FMP ExpertsメーリングリストのMikhail Edoshinから教わったチップスです。
Tip #3: NOT演算子でロジックを単純化する
「次の場合にオブジェクトを隠す」の機能が、逆の「次の場合にオブジェクトを表示する」だったらよかったのにと考えたことはないですか? 簡単な例を示します。あるレイアウトオブジェクトを、特定のレイアウトでだけ表示したいという場合です。
class::Name = “Kindergarten”
or
class::Size < 20
当然この計算式をそのまま「次の場合にオブジェクトを隠す」の条件に適用したいと思うでしょう。
class::Name <> "Kindergarten" and class::Size >= 20
しかしそれは、解決したい現実世界の問題を特定した後に、改めてそのまったく逆の場合を定義し直すことになります。これはロジカルシンキングの訓練にはいいかも知れませんが、「次の場合にオブジェクトを隠す」の条件式を次のように定義できれば簡単だと思いませんか?
Not ( class::Name = "Kindergarten" or class::Size < 20 )
もちろん条件式が単純であればどちらにしても大した違いはないかも知れませんが、条件式が複雑になればなるほど、このアプローチは効果が出るでしょう。
Tip #4: Get ( ファイル名 ) の代わりに””を使う
デザイン関数の多くは1つ目の引数にファイル名をとります。開発者は、ファイル名を決め打ちする代わりに、現在のファアイルを特定するために通常 Get ( ファイル名 ) を使用します。もちろんこれは非常に良い方法ですが、代わりにダブルクオーテーションのペアを使うこともできます。
たとえばValueListItems関数では、
以下のような値一覧がある場合、
次のいずれも同じ結果を返します。
Tip #5: 上のチップスへの追記
なお、空のダブルクオーテーションのトリックは、レイアウト名が引数の場合は、一見動作するように見えても、ファイル名の場合と同じように動作するわけではないので注意してください。たとえば、FieldNames関数とFieldIDs関数はどちらも以下の2つの引数をとります。
- ファイル名
- レイアウト名
Get ( ファイル名 )関数の代わりに””を使うことはできますが、Get ( レイアウト名 )の代わりに””を使うと、そのファイルの最初のテーブル (つまりファイル内のもっとも古いテーブル)上のすべてのフィールドが返されます。言い換えると、表面上正しく見えるものが、(たまたまその最初のテーブルに基づくレイアウトにいる場合を除いて)実際にはそうではないということになります。
レイアウト名を引数に持つ以下の4つのデザイン関数では、
- FieldBounds
- FieldRepetitions
- FieldStyle
- LayoutObjectNames
Get ( レイアウト名 )の代わりに””を使用した場合、何も返されません。
Tip #6: 上のチップスへの追記2
この話題を終わる前に、FieldNames関数とFieldIDs関数に触れないわけにはいかないでしょう。
- レイアウト名の引数の部分にテーブルオカレンス名を指定して、
かつ - ファイルにそのテーブルオカレンス名と同じ名前のレイアウトが存在しない場合、
これらの関数は、特定のレイアウトではなく、元となるテーブルのすべてのフィールドを参照します。たとえばあるソリューションにSettingsという名前のテーブルオカレンスが存在し、Settingsというレイアウトが存在しない場合、テーブルのすべてのフィールド名を返します。
しかしSettingsという名前のレイアウトを作成し、いくつかフィールドをレイアウト上に配置すると、当然ですがレイアウトの方が優先されます。
Tip #7: FM14のチェックマークをFM 12,13のソリューションで使用する
未だにFM12または13を使いながら、FM14のチェックマークオプションが羨ましいと感じている方へ。ファイルをFM14で開いて、チェックボックスの設定でチェックマークを表示するよう定義すると、
なんとチェックマークがFM12でも利用できます。
そして13でも。
Tip #8: 「レコードのインポート」スクリプトステップの複製 vs コピー
スクリプトステップをコピーするとコンピュータのクリップボードの内容が上書きされてしまうという点は除いて、既存の「レコードのインポート」スクリプトステップをコピー&ペーストするよりも複製する方がいい理由はあるでしょうか?
答えは、何をしたいか・何を期待するかによって「YES」でも「NO」でもあります。2行目のオリジナルのステップを詳しく見てみましょう。
「照合名順」が指定されていることに注目してください。次に5行目の複製されたバージョンを見てみましょう。
予想どおり、内容は2行目のオリジナルと同じです。では8行目のスクリプトステップ(2行目をコピー&ペーストしたもの)はどうでしょうか?
これは一体どういうことでしょう? 移動の途中で「照合名順」の情報は失われました。そして理由は以下のとおりです。スクリプトステップをペーストしたとき、実際に裏でペーストしているのはXMLコードであり、「レコードのインポート」のXML表現には「配置順」の設定は含まれていません。基本的に「レコードのインポート」スクリプトステップをペーストした場合、配置順は常に「最後に使用した順序」になります。
一方スクリプトステップを複製した場合、FileMakerは別の内部機構を利用して配置順の情報も保持されます。
関連情報として、以下はFileMaker Pro Advancedを使ってDDR (データベースデザインレポート)を生成した場合に、オリジナルの「レコードのインポート」スクリプトステップがどう表示されるかを示したものです。ソースフィールドは作成順で(名前順ではなく)並び、配置順の情報はありません。
Tip #9: コンテキストメニューからの検索/絞り込み/拡大
フィールドを右クリックして「一致するレコードを検索」、「対象レコードの絞り込み」、「対象レコードの拡大」を選択できることはすでにご存知かと思います。
結果として、クリックしたフィールドに一致するレコードを検索できます。
ここで、選択されたテキストに対しても同じ操作ができることをご存知でしたか? 私はつい最近(しかも偶然に)見つけたので、もしかしたら初めて知ったという方もいるかも知れません。たとえば、“Class”という単語を選択して「対象レコードを拡大」を選択すると、
結果は以下のようになります。
Tip #10: 存在しないレイアウトをトラップする
[注: 理由はこの後に述べていますが、このチップスを自分で試す場合は必ずバックアップ・コピーに対して行ってください。]次のような、データ整理の手順を自動化したスクリプトがあるとします。
何らかの理由で「session」レイアウトが削除された場合、どうなるでしょうか?
- FileMakerは存在しないレイアウトに移動することができないので、現在のレイアウトにとどまる
- (エラー処理のオン・オフに関わらず)エラーダイアログは表示されない
- アクティブなテーブルのすべてのレコードが削除される
推奨: 次の処理に進む前に、それが安全かどうかを確認してください。エラー処理の手順は複雑になる場合もあり、この記事ですべてカバーすることはできませんが、少なくとも以下のような処理を入れることができます。
ちなみにレイアウトが存在しない場合のエラーコードは105です。FileMakerのエラーコードの全リストは次のリンクから参照できます。Error Code Reference Guide
Tip #11: 文字の「?」はブール値ではtrueと評価される
なぜこれがチップスになるのかというと、以下のようなコードをよく目にするからです。
If [ $theBooleanVar ] Delete Record [no dialog] End If
変数の$theBooleanVarが“?”になることは絶対にないと保証できればこのままで問題ないですが、If文に少し追加して以下のようにするのは大した手間ではないはずです。
If [ $theBooleanVar = 1 ] Delete Record [no dialog] End If
“?”がTRUEに評価されるという根拠を以下に示します。
想定外で“?”が返される2つの例:
- カスタム関数が壊れている場合、あるいは再帰の上限を超えた場合
- 文法エラーがあるExecuteSQL文
今回はここまでです。