単一値フィールドについて尋ねているだけでなく、テーブル関係についても尋ねているため、質問はかなり奇妙です。非常に厳密な解釈では、複数値フィールド (MVF) は、コンマ区切りの項目で満たされた単一の TextBox に置き換えることができます...テーブル関係は必要ありません。代わりに、「単一値」フィールドによって、質問は、関連する各行の各フィールドが単一の値を持つ複数テーブル関係の標準フィールドを意味すると仮定します。ただし、各プライマリ レコードは、関連付けられた値テーブル内の複数の行に関連付けることができ、MVF の目的全体を維持できます。
MVF の可能な置き換えを説明するために、以下のデータベースの概要を検討してください。すべての可能なプロパティや基本的なオブジェクトの作成方法を含めているわけではなく、目的の動作を作成するために必要なものだけを示しています。「空白を埋める」ための十分な Access の知識があり、基本的なコードや SQL を恐れていないことを前提としています。
基本構造は、1) プライマリ テーブル、2) 「値リスト」テーブル、3) 多対多の関係を定義するために使用されるジャンクション テーブルの 3 つのテーブルで構成されます。
- 顧客テーブル
CustomerID: autonumber、プライマリ
CustomerName: 短いテキスト
- コード テーブル
コード: 短いテキスト、長さ 5、主キー
説明: 短いテキスト
- [Customer Codes] テーブル
CustomerID: long
Code: short text
テーブル間の関係を作成します。これには、テーブルに適切なインデックスを定義する必要があります (ここでは詳しく説明しません)。
- Customer テーブルから [Customer Codes] テーブル
CustomerID -> CustomerID フィールド (整合性の強制を有効化)
- Code Table to [Customer Codes] Table
Code -> Code fields (強制整合性を有効化)
(値テーブル [コード テーブルなど] テーブル用に別の ID フィールドを作成することもできますが、それは後のクエリやコントロールなどを複雑にするだけです。そのような場合、ジャンクション テーブルには値ではなく別の ID フィールドが含まれます。 )
標準の VBA モジュールで、次のような関数を作成します。
Public Function GetCodeList(ByVal CustomerID As Integer) As String
Dim sSQL As String
Dim qry As QueryDef
Dim rs As Recordset2
sSQL = "PARAMETERS [CustID] LONG;" & _
" SELECT * FROM [Customer Codes] WHERE [CustomerID] = [CustID]"
Set qry = CurrentDb.CreateQueryDef("", sSQL)
qry.Parameters("CustID") = CustomerID
Set rs = qry.OpenRecordset(dbOpenForwardOnly, dbReadOnly)
Dim sCodes As String
sCodes = ""
Dim bFirst As Boolean
bFirst = True
Do Until rs.EOF
sCodes = sCodes & IIf(bFirst, "", ",") & rs("Code")
bFirst = False
rs.MoveNext
Loop
rs.Close
qry.Close
GetCodeList = sCodes
End Function
重複行のないプライマリ テーブルの便利なクエリには、何らかの集計クエリ (Group By、Count など) を作成する必要があります。単純な選択は、たとえば、1 つのクエリで実行できます。
SELECT Customer.CustomerID, Customer.[CustomerName], GetCodeList([CustomerID]) AS Codes, Count(Customer.CustomerID) AS CountOfID
FROM Customer LEFT JOIN [Customer Codes] ON Customer.ID = [Customer Codes].CustomerID
WHERE ((([Customer Codes].Code)="Current" Or ([Customer Codes].Code)="Free"))
GROUP BY Customer.ID, Customer.[CustomerName], GetCodeList([ID]);
より複雑な選択では、複数のクエリが必要になる場合があります。最初に適切なレコードを選択するクエリと、プライマリ テーブルを最初のクエリに結合するクエリです。しかし、正直なところ、これらのタイプのクエリは、複数値フィールドで選択するために必要なものほど複雑ではありません。実際、MVF のクエリ構文は非標準であり、ジャンクション テーブルと多対多のリレーションシップを使用する以上に、かなり複雑で混乱を招く可能性があります。舞台裏では、Access は基本的に私が概説したのと同じことを行っていますが、Access は非常に多くの詳細を隠しているため、一部のクエリはさらに困難になっています。
フォームでの複数値の表示と選択に関して、複数値の ComboBox を正確に模倣することはできません。主な理由は、基本的な Access Combobox には、チェックボックスを表示する機能を備えた複数選択オプションがないためです。ただし、バインドされていない ListBox にプロパティ [Multi Select] = Simple を設定することはできます。Form_Load イベントで、ListBox.AddItem メソッドを使用して、使用可能な値 (サンプル テーブルのコードなど) をリストボックスに追加します。次に、Form_Current、Form_AfterUpdate、Form_Undo イベントで、選択した値を表示および/または保存するコードを追加できます。これには、おそらくここでの範囲を超えるコードがさらに必要です。
技術的には、MVF を別の実装に「移動」することについて質問されました。要点は、値テーブル (例のコード テーブルなど) に MVF リストの同じ値を入力することです。これは手動のプロセスである可能性がありますが、MVF の ComboBox がどのように設定されているかによって異なります。次に、同じプライマリ レコードの各 MFV をジャンクション テーブル ([顧客コード] など) にコピーするクエリを記述します。
INSERT INTO [Customer Codes] ( CustomerID, Code )
SELECT Customer.CustomerID, Customer.TestMVF.Value
FROM Customers
WHERE (((Customers.TestMVF.Value) Is Not Null));
完全な実装は全体として単純な作業ではありませんが、MVF で問題が多すぎる場合や、別のデータベースに移行したい場合は、この種の変更を理解する必要があります。