Access 2010以降、Accessは添付ファイルデータ型をサポートしてきました。これは、表面上は小さな画像やファイルを保存するための便利な機能のようです。ただし、グーグルですばやく検索すると、通常は避けるのが最善であることがわかります。これはすべて、添付ファイルのデータ型が実際には複数値フィールド(MVF)であるという事実に要約され、これらにはいくつかの問題があります。 1つは、クエリを使用して一度に複数のレコードを挿入または更新することはできません。実際、そのようなデータ型を含むテーブルでは、多くのコードを実行する必要があります。そのため、このようなデータ型を通常は使用しないようにしています。
ただし、問題があります。画像ギャラリーとテーマを使用するのが大好きです。どちらもシステムテーブルMSysResources
に依存しています。 残念ながら、添付ファイルのデータ型を使用します。 MSysResources
を使用したいので、これにより標準ライブラリのリソースを管理する際に問題が発生しました。 ただし、簡単に更新したり、まとめて挿入したりすることはできません。
添付ファイルのデータ型(およびMVF)を使用すると、MVFフィールドを処理するときに「行ごとの行」プログラミングを使用する必要があります。 LoadFromFile を使用する必要があるため、添付ファイルフィールドとは2つになります。コード> または
SaveToFile
メソッド。 Microsoftには、これらの方法に関する例が記載された記事があります。したがって、新しいレコードを追加するときは、ファイルシステムを操作する必要があります。すべての状況で常に望ましいとは限りません。これで、あるテーブルから別のテーブルにコピーする場合、次のようにすることでファイルシステムのバウンスを回避できます。
Dim SourceParentRs As DAO.Recordset2 Dim SourceChildRs As DAO.Recordset2 Dim TargetParentRs As DAO.Recordset2 Dim TargetChildRs As DAO.Recordset2 Dim SourceField As DAO.Field2 Set SourceParentRs = db.OpenRecordset("TableWithAttachmentField", dbOpenDynaset) Set TargetParentRs = db.OpenRecordset("AnotherTableWithAttachmentField", dbOpenDynaset, dbAppendOnly) Do Until SourceParentRs.EOF TargetParentRs.AddNew For Each SourceField In SourceParentRs.Fields If SourceField.Type <> dbAttachment Then TargetParentRs.Fields(SourceField.Name).Value = SourceField.Value End If Next TargetParentRs.Update 'Must save record first before can edit MVF fields TargetParentRs.Bookmark = TargetParentRs.LastModified Set SourceChildRs = SourceParentRs.Fields("Data").Value Set TargetChildRs = TargetParentRs.Fields("Data").Value Do Until SourcechildRs.EOF TargetChildRs.AddNew Const ChunkSize As Long = 32768 Dim TotalSize As Long Dim Offset As Long TotalSize = SourceChildRs.Fields("FileData").FieldSize Offset = TotalSize Mod ChunkSize TargetChildRs.Fields("FileData").AppendChunk(SourceChildRs.GetChunk(0, Offset) Do Until Offset > TotalSize TargetChildRs.Fields("FileData").AppendChunk(SourceChildRs.GetChunk(Offset, ChunkSize) Offset = Offset + ChunkSize Loop TargetChildRs.Update SourceChildRs.MoveNext Loop TargetParentRs.Update SourceParentRs.MoveNext Loop
聖なるループ、バットマン!これは多くのコードであり、すべて添付ファイルを1つのテーブルから別のテーブルにコピーするためのものです。ファイルシステムをバウンスしませんが、非常に低速です。私たちの経験では、1つの添付ファイルを含む1000レコードのテーブルには、分かかる場合があります。 処理するだけです。さて、サイズを考えると、これはかなり特大です。アタッチメント付きのテーブルはそれほど大きくありません。実際、実験してみましょう。データシートを介してコピーして貼り付けるとどうなるか見てみましょう:
したがって、コピーと貼り付けは実質的に瞬時に行われます。明らかに、貼り付けで使用されるコードは、VBAで使用するコードと同じではありません。ただし、インタラクティブに実行できれば、VBAでも実行できると確信しています。 VBAでインタラクティブな貼り付けの速度を再現できますか?答えはイエスであることが判明しました、私たちはできます!
…でスピードアップ。 XML?
驚くべきことに、添付ファイルを含むデータをコピーする最速の方法を提供する方法は、XMLファイルを使用することです。制限の回避策を除いて、XMLファイルを入手できないことを認めます。平均して、XMLファイルは他のファイル形式に比べて比較的低速ですが、この場合、XMLには1つの大きな利点があります。 MVFの記述に問題はありません。 XMLファイルを作成し、XMLファイルのインポート/エクスポートで得られる機能を調べてみましょう。
XMLファイルを保存するためのパスを設定するための通常のエクスポートウィザードダイアログの後に、次のようなダイアログが表示されます。
次に[その他のオプション...]ボタンをクリックすると、代わりに次のダイアログが表示されます:
このダイアログから、何が可能かについての手がかりがさらにいくつかわかります。つまり:
- フィルターを適用して、テーブル全体またはテーブルのサブセットのみをエクスポートするオプションがあります
- XML出力を変換できます。
- テーブルの内容に加えて、スキーマを記述できます。
スキーマを埋め込むのが最善だと思います。デフォルトではエクスポートされますが、別のファイルとしてエクスポートされます。ただし、これはエラーが発生しやすく、XMLファイルにXSDファイルを含めるのを忘れる可能性があります。これは、次の[スキーマ]タブで変更できます:
エクスポートを終了して、結果のXMLファイルのデータを簡単に見てみましょう。
添付ファイルはData
内に記述されていることに注意してください サブツリーとファイルの内容はbase-64でエンコードされています。 XMLファイルをインポートしてみましょう。インポートウィザードを実行すると、次のダイアログが表示されます:
次の機能に注意してください:
- エクスポートと同様に、XMLを変換するオプションがあります。
- 構造、データ、またはその両方をインポートするかどうかを制御できます
その後、XMLファイルのインポートを完了すると、コピーアンドペースト操作と同じくらい高速であることがわかります。
添付ファイル付きの複数のレコードをコピーするためのより良い方法があることがわかりました。しかし、この状況では、インタラクティブではなく、プログラムでこれを実行したいと考えています。今と同じことをすることができますか?繰り返しますが、答えはイエスです。同じことを行うには複数の方法がありますが、最も簡単な方法は、アプリケーション
に追加された3つの新しいメソッドを使用することだと思います。 Access 2010以降のオブジェクト:
-
ExportXML
メソッド -
TransformXML
メソッド -
ImportXML
メソッド
ExportXML
に注意してください メソッドは、さまざまなオブジェクトからのエクスポートをサポートします。ただし、ここでの目的は、添付ファイルフィールドを持つテーブルのレコードをまとめてコピーまたは更新できるようにすることであるため、使用するのに最適なオブジェクトタイプは保存されたクエリです。保存されたクエリを使用して、挿入または更新する行を制御したり、出力を整形したりすることもできます。 MSysResources
のスキーマ設計を見ると 以下の表:
潜在的な問題があります。テーマや画像を使用する場合は常に、IDではなく名前でアイテムを参照します。ただし、 Name
列は一意ではなく、テーブルの主キーではありません。したがって、レコードを追加または更新するときは、 Name
で一致させる必要があります Id
ではなく列 桁。つまり、エクスポートするときに、おそらく Id
を含めるべきではありません。 列であり、 Name
の一意のリストのみをエクスポートする必要があります リソースが突然「Open.png」から「Close.png」などに変わってしまわないようにするためです。
次に、 MSysResources
にインポートするレコードのソースとして機能するクエリを作成します。 テーブル。レコードのサブセットへのフィルタリングを示すために、このSQLから始めましょう:
SELECT e.Data, e.Extension, e.Name, e.Type FROM Example AS e WHERE e.Name In ("blue","red","green");
次に、それを qryResourcesExport
として保存します 。次に、XMLをエクスポートするためのVBAコードを記述できます:
Application.ExportXML _ ObjectType:=acExportQuery, _ DataSource:="qryResourcesExport", _ DataTarget:="C:\Path\to\Resources.xml", _ OtherFlags:=acEmbedSchema
これは、最初にインタラクティブに行ったエクスポートをエミュレートします。
ただし、結果のXMLをインポートする場合、既存のテーブルにデータを追加するオプションしかありません。追加するテーブルを制御することはできません。同じ名前のテーブルまたはクエリテーブルが検索されます(例: qryResourcesExport
そのクエリにレコードを追加します。クエリが更新可能であれば、問題はなく、 Example
に挿入されます。 クエリの基になっています。しかし、使用するソースクエリが更新できないか、存在しない可能性がある場合はどうなりますか?どちらの場合も、XMLファイルをそのままインポートすることはできません。インポートに失敗するか、 qryResourcesExport
という名前の新しいテーブルを作成することになります。 それは私たちを助けません。そして、 Example
からデータをコピーする場合はどうでしょうか。 MSysResources
へ ? 例
にデータを追加したくない テーブル。
ここでTransformXML
方法が助けになります。 XML変換の記述方法に関する完全な説明は範囲を超えていますが、変換を説明するXSLTスタイルシートの記述方法に関する十分なリソースを見つけることができるはずです。 XSLTの検証にも使用できるオンラインツールがいくつかあります。これが1つです。 XMLファイルがレコードを追加するテーブルを制御したいという単純なケースでは、このXSLTファイルを使い始めることができます。その後、次のVBAコードを実行できます。
Application.TransformXML _ DataSource:="C:\Path\to\Resources.xml", _ TransformSource:="C:\Path\to\ResourcesTransform.xslt", _ OutputTarget:="C:\Path\to\Resources.xml", _ WellFormedXMLOutput:=True, _ ScriptOption:=acEnableScript
元のXMLファイルを変換されたXMLファイルに置き換えることができます。これにより、 MSysResources
に挿入されます。 (おそらく存在しないクエリ/テーブル) qryResourcesExport
ではなくテーブル 。
次に、更新を処理する必要があります。実際に新しいレコードとMSysResources
を追加しているためです テーブルには重複する名前に対する制約はありません。同じ名前の既存のレコードが最初に削除されるようにする必要があります。これは、次のような同等のクエリを作成することで実現できます。
DELETE FROM MSysResources AS r WHERE r.Name In ("blue","red","green");
次に、VBAコードを実行する前に最初に実行します:
Application.ImportXML DataSource:="C:\Path\to\Resources.xml", ImportOptions:=acAppendData
XMLファイルが変換されたため、 ImportXML
メソッドはデータをMSysResources
に挿入します ExportXML
で使用した元のクエリではなくテーブル 方法。既存のテーブルにデータを追加するように指定します。ただし、テーブルが存在しない場合は作成されます。
これにより、元のレコードセットと子レコードセットのVBAコードと比較してはるかに高速な添付ファイルフィールドを使用して、テーブルの一括更新/挿入を実現しました。お役に立てば幸いです。また、Accessアプリケーションの開発についてサポートが必要な場合は、お気軽にお問い合わせください!