sql >> データベース >  >> RDS >> Access

添付ファイルフィールドを持つテーブルの一括挿入または更新

    Access 2010以降、Accessは添付ファイルデータ型をサポートしてきました。これは、表面上は小さな画像やファイルを保存するための便利な機能のようです。ただし、グーグルですばやく検索すると、通常は避けるのが最善であることがわかります。これはすべて、添付ファイルのデータ型が実際には複数値フィールド(MVF)であるという事実に要約され、これらにはいくつかの問題があります。 1つは、クエリを使用して一度に複数のレコードを挿入または更新することはできません。実際、そのようなデータ型を含むテーブルでは、多くのコードを実行する必要があります。そのため、このようなデータ型を通常は使用しないようにしています。

    ただし、問題があります。画像ギャラリーとテーマを使用するのが大好きです。どちらもシステムテーブルMSysResourcesに依存しています。 残念ながら、添付ファイルのデータ型を使用します。 MSysResources を使用したいので、これにより標準ライブラリのリソースを管理する際に問題が発生しました。 ただし、簡単に更新したり、まとめて挿入したりすることはできません。

    添付ファイルのデータ型(およびMVF)を使用すると、MVFフィールドを処理するときに「行ごとの行」プログラミングを使用する必要があります。 LoadFromFile または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アプリケーションの開発についてサポートが必要な場合は、お気軽にお問い合わせください!


    1. ArrayField内のDjangoJSONField

    2. MySQLPHPの非互換性

    3. PostgreSQLネストされたJSONクエリ

    4. MySQLでユーザーと認証を管理する方法