セット
セットは、レコードのセレクションを操作するための強力かつ迅速な手段を提供します。セットの作成、カレントセレクションとの関連付け、セットの保存・読み込み・消去といった機能に加えて、4D は 3 つの標準的なセット操作を提供します:
- 交差(Intersection)
- 和(Union)
- 差(Difference)
セットとカレントセレクション
セットは、レコードのセレクションのコンパクトな表現です。セットの概念は、カレントセレクションの概念と密接に結びついています。セットは一般に次の目的で使用されます:
- 順序が重要でない場合に、セレクションを保存して後で復元する
- ユーザーが画面上でおこなったセレクション(
UserSet)にアクセスする - セレクション間で論理演算をおこなう
カレントセレクションは、現在選択されている各レコードを指す参照のリストです。このリストはメモリ内に存在します。現在選択されているレコードのみがリストに含まれます。セレクションは実際にはレコードを含んでおらず、レコードへの参照のリストのみを含みます。レコードへの各参照は、メモリ内で 4 バイトを占めます。テーブルで作業するとき、常にカレントセレクション内のレコードを扱います。セレクションがソートされると、参照のリストのみが再配置されます。1 つのプロセス内で、各テーブルにはカレントセレクションが 1 つだけ存在します。
カレントセレクションと同様に、セットもレコードのセレクションを表します。セットは、各レコードに対して非常にコンパクトな表現を使用することでこれをおこないます。各レコードは 1 ビット(1 バイトの 8 分の 1)で表されます。コンピューターはビットに対する操作を非常に高速に実行できるため、セットを使用する操作は非常に高速です。セットは、レコードがセットに含まれているかどうかにかかわらず、テーブル内のすべてのレコードにつき 1 ビットを含みます。実際、各ビットは、レコードがセット内にあるかどうかに応じて 1 または 0 になります。
セットは RAM 領域の点で非常に経済的です。セットのサイズ(バイト単位)は、常にテーブル内のレコードの総数を 8 で割った値に等しくなります。たとえば、10,000 件のレコードを含むテーブルに対してセットを作成すると、そのセットは 1,250 バイト、すなわち RAM で約 1.2K を占めます。
各テーブルには多数のセットを持つことができます。実際、セットはデータベースとは別にディスクに保存できます。セットに属するレコードを変更するには、まずそのセットをカレントセレクションとして使用し、次にレコードを変更する必要があります。
セットは決してソート順にはなりません — レコードはセットに属しているかどうかが単に示されるだけです。一方、名前付きセレクションはソート順ですが、ほとんどの場合により多くのメモリを必要とします。名前付きセレクションの詳細については、「名前付きセレクション」セクションを参照してください。
セットは、セットが作成された時点でどのレコードがカレントレコードであったかを「記憶」します。次の表は、カレントセレクションとセットの概念を比較したものです:
| 比較 | カレントセレクション | セット |
|---|---|---|
| テーブルごとの数 | 1 | 0 から複数 |
| ソート可能 | はい | いいえ |
| ディスクに保存可能 | いいえ | はい |
| レコードあたりの RAM(バイト単位) | 選択されたレコード数 * 4 | レコードの総数/8 |
| 結合可能 | いいえ | はい |
| カレントレコードを含む | はい | はい、セットが作成された時点のもの |
セットを作成すると、それは作成元のテーブルに属します。セット操作は、同じテーブルに属するセット間でのみ実行できます。
セットはデータから独立しています。つまり、ファイルに変更が加えられた後、セットはもはや正確でなくなる可能性があります。セットを不正確にする操作は数多くあります。たとえば、ニューヨーク市のすべての人のセットを作成し、その後それらのレコードの 1 つのデータを「ボストン」に変更しても、セットは変わりません。セットはレコードのセレクションの表現にすぎないためです。レコードを削除して新しいものに置き換えることも、データを圧縮することと同様に、セットを変更します。セットの正確さが保証されるのは、元のセレクションのデータが変更されていない間だけです。
プロセスセットとインタープロセスセット
次の 3 種類のセットを持つことができます:
- プロセスセット:プロセスセットは、それが作成されたプロセスによってのみアクセスできます。
LockedSetはプロセスセットです。プロセスセットは、プロセスメソッドが終了するとすぐに消去されます。プロセスセットの名前には特別なプレフィックスは必要ありません。 - インタープロセスセット:セットの名前が (<>) 記号 — 「小なり」記号に続けて「大なり」記号 — で始まる場合、そのセットはインタープロセスセットです。インタープロセスセットは、データベースのすべてのプロセスから「見える」状態です。 クライアント/サーバーモードでは、インタープロセスセットは、それが作成されたマシン(クライアントまたはサーバー)のプロセスから「見える」状態です。 インタープロセスセットの名前は、データベース内で一意でなければなりません。
- ローカルセット/クライアントセット:ローカル/クライアントセットは、クライアント/サーバーモードでの使用を目的としています。ローカル/クライアントセットの名前は、常にドル記号 ($) で始まります -- ただし UserSet システムセットは例外です。他の種類のセットとは異なり、ローカル/クライアントセットはクライアントマシンに格納されます。
- セット名の最大サイズは 255 文字です(<> および $ 記号を除く)。
- クライアント/サーバーモードでのセットの使用に関する詳細については、「4D Server、セットと名前付きセレクション」を参照してください。
セットの可視性
次の表は、セットのスコープおよび作成された場所に応じた可視性の原則を示しています:
| クライアントプロセス | 同一クライアント上の他のプロセス | 他のクライアント | サーバープロセス | サーバー上の他のプロセス | |
|---|---|---|---|---|---|
| クライアントプロセスでの作成 | |||||
| $test | X | ||||
| test | X | X(Trigger) | |||
| <>test | X | X | |||
| サーバープロセスでの作成 | |||||
| $test | X | ||||
| test | X | ||||
| <>test | X | X |
セットとトランザクション
セットは トランザクション の内部で作成できます。トランザクションの内部で作成されたレコードのセットと、トランザクションの外部で作成または変更されたレコードのセットを作成することが可能です。トランザクションが終了すると、トランザクション中に作成されたセットは消去すべきです。特にトランザクションがキャンセルされた場合、そのセットはレコードの正確な表現ではない可能性があるためです。
例題
次の例は、人物に関する情報を含むテーブルから重複レコードを削除します。For...End for ループがすべてのレコードを移動し、カレントレコードを前のレコードと比較します。名前、住所、郵便番号が同じ場合、そのレコードはセットに追加されます。ループの終わりに、そのセットがカレントセレクションになり、(古い)カレントセレクションが削除されます:
CREATE EMPTY SET([People];"Duplicates")
// 重複レコード用の空のセットを作成
ALL RECORDS([People])
// すべてのレコードを選択
// 重複が隣り合うように、郵便番号、住所、名前で
// レコードをソート
ORDER BY([People];[People]ZIP;>;[People]Address;>;[People]Name;>)
// 前のレコードのフィールドを保持する変数を初期化
$Name:=[People]Name
$Address:=[People]Address
$ZIP:=[People]ZIP
// 最初のレコードと比較するため 2 番目のレコードへ移動
NEXT RECORD([People])
For($i;2;Records in table([People]))
// 2 番目からレコードをループ
// 名前、住所、郵便番号が前のレコードと同じ場合、
// それは重複レコードです。
If(([People]Name=$Name) & ([People]Address=$Address) & ([People]ZIP=$ZIP))
// カレントレコード(重複)をセットに追加
ADD TO SET([People];"Duplicates")
Else
// 次のレコードとの比較のためにこのレコードの名前、住所、郵便番号を保存
$Name:=[People]Name
$Address:=[People]Address
$ZIP:=[People]ZIP
End if
// 次のレコードへ移動
NEXT RECORD([People])
End for
// 見つかった重複レコードを使用
USE SET("Duplicates")
// 重複レコードを削除
DELETE SELECTION([People])
// セットをメモリから削除
CLEAR SET("Duplicates")
メソッドの終わりにレコードを即座に削除する代わりに、それらを画面に表示したり印刷したりして、より詳細な比較をおこなうこともできます。
UserSet システムセット
4D は UserSet という名前のシステムセットを管理しており、これはユーザーが画面上でハイライトした最新のレコードのセレクションを自動的に格納します。したがって、MODIFY SELECTION または DISPLAY SELECTION でレコードのグループを表示し、その中からユーザーに選択してもらい、その手動選択の結果を、あなたが名前を付けるセレクションまたはセットに変換できます。
その名前が文字 "$" で始まらないにもかかわらず、UserSet システムセットはクライアントセットです。そのため、INTERSECTION、UNION、DIFFERENCE を使用する際は、UserSet をクライアントセットとのみ比較するようにしてください。
プロセス には UserSet が 1 つだけ存在します。各テーブルが独自の UserSet を持つわけではありません。テーブルに対してレコードのセレクションが表示されると、UserSet はそのテーブルに「所有」されるようになります。
4D は、デザインモードで表示されるリストフォーム、または MODIFY SELECTION や DISPLAY SELECTION コマンドを使用して表示されるリストフォームに対して UserSet セットを管理します。ただし、このメカニズムは サブフォーム に対しては有効ではありません。
次のメソッドは、レコードを表示し、ユーザーにそのうちのいくつかを選択させ、その後 UserSet を使用して選択されたレコードを表示する方法を示しています:
// すべてのレコードを表示し、ユーザーが任意の数を選択できるようにします。
// その後、UserSet を使用してカレントセレクションを変更し、このセレクションを表示します。
FORM SET OUTPUT([People];"Display") // 出力フォームを設定
ALL RECORDS([People]) // すべての人物を選択
ALERT("Ctrl または Command を押しながらクリックして、必要な人物を選択してください。")
DISPLAY SELECTION([People]) // 人物を表示
USE SET("UserSet") // 選択された人物を使用
ALERT("次の人物を選択しました。")
DISPLAY SELECTION([People]) // 選択された人物を表示
LockedSet システムセット
APPLY TO SELECTION、DELETE SELECTION、ARRAY TO SELECTION、JSON TO SELECTION コマンドは、マルチプロセス環境で使用されると、LockedSet という名前のセットを作成します。
検索コマンドも、「検索してロック」コンテキストでロックされたレコードを見つけた場合に、LockedSet システムセットを作成します(SET QUERY AND LOCK コマンドを参照)。
LockedSet は、コマンドの実行中にどのレコードがロックされていたかを示します。