Microsoft Access 掲示板

2次配列で格納したデータを、フィールド名で呼び出す方法。

9 コメント
views
4 フォロー

sptx、sbj、pymt、fwd、datという5つのフィールド名のデータを2次配列に格納します。

    adoRs.Open strSQL, adoCn, Options:=adCmdTableDirect 'フィールド名も含めてRecordSetへ
とした後、
    myArray = adoRs.GetRows
で、sptx、sbj、pymt、fwd、datという5つのフィールドのデータを2次配列に格納します。

    x = 0
    i = 0

    For x = 0 To RcCnt - 1
    "n1-" & i = myArray(0, x)
    "n2-" & i = myArray(1, x)
    "n3-" & i = myArray(2, x)
    "n4-" & i = myArray(3, x)
    "n5-" & i = myArray(4, x)
     x = x + 1
     i = i + 1
    Next

とすれば、データは取り出せるのですが、
実際の場合は、フィールド数が多い場合が多いので、数字で指定するのは非効率的です。
フィールド名で指定してデータを取り出すのが、現実的な方法だと思います。
が、
Acs = adoRs.Fields(sbj(i))
など、いろいろ試してみたのですが、サッパリです。
よろしくお願い致します。

タークン
作成: 2024/01/18 (木) 17:57:02
通報 ...
1

sptx、sbj、pymt、fwd、datという5つのフィールド名のデータを2次配列に格納します。

myArray = adoRs.GetRows

具体的にどのような目的から 2 次元配列を用いようとされているのでしょうか。

"n1-" & i = myArray(0, x)

少なくとも、上記のコードをそのまま記述すればコンパイルエラーが発生します。

実際の場合は、フィールド数が多い場合が多いので、数字で指定するのは非効率的です。
フィールド名で指定してデータを取り出すのが、現実的な方法だと思います。

2 次元配列を使用する目的が不明ですので、今のところ評価のしようがありません。

2

レコードセットは配列の上位互換だと思いますが、なぜ配列で処理する必要があるのでしょう?レコードセットならフィールド名でデータを取り出せます。どのような目的で配列にするのでしょうか。

やるとするなら、連想配列(Dictionary)にフィールド名と何列目かを格納して、参照することになるかな?

  Dim dic As Object
  Set dic = CreateObject("Scripting.Dictionary")
  Dim fld As ADODB.Field, i As Long
  For Each fld In adoRs.Fields
   dic(fld.Name) = i
    i = i + 1
  Next fld

  Debug.Print myArray(dic("フィールド名"), x)
3
タークン 2024/01/19 (金) 14:38:38 7a0a1@2705a

まず、データと一緒に、フィールド名を格納することはできなかったようでした。
認識不足でした。

ACCESSのテーブルの、何番目のフィールドか調べたいわけではありません。
レコードセットは、フィールド名でデータを取り出せるので、
事前に、フィールドの並び順をカウントしておけば良いのですが、
よく単純な数え間違えが起こります。
何番目に、どのフィールドをおいて呼び出したのか、
確認するコードを加えれば済む話ではあります。
なのですが、フィールド名でデータを特定するのがベストなので、できればそうしたいということです。

と言っても、データを整理して一括で貼り付けないと、負荷はほとんど変わりません。
この処理段階の方が、何倍もミスを犯しやすいので、取るに足らないこだわりかもしれないです。

4
りんご 2024/01/19 (金) 15:06:04 07313@0e907 >> 3

怪しい民間療法みたいな街角勉強会に引っかかっているんじゃないかしら?accessのようなデータベースがまだ発明されていない時代に、流行っていた思想は廃れたはずですが。

5
hatena 2024/01/19 (金) 15:08:03 修正

何番目に、どのフィールドをおいて呼び出したのか、
確認するコードを加えれば済む話ではあります。

そのコードを前の回答で提示したつもりですが。

どちらにしても、
2 次元配列をどのように利用しようとしているか。
レコードセットではだめなのか、その辺の説明がないと、
これ以上、議論のしようがないように思います。

6

データと一緒に、フィールド名を格納することはできなかった

データを整理して一括で貼り付けないと

  • そもそもそのプロシージャはどのファイルのどのモジュールに記述されているのか( Access データベースファイル上の標準モジュール、Excelマクロ有効ブックの標準モジュールなど)。

  • 取得したレコードセット(の各フィールドの名前と値)をどこに、どのような形で貼り付けようとしているのか。

以上の前提についてのご説明がない限り、何を問題視されているのか不明瞭なままです。

例えば「ある accdb ファイル上に存在するテーブルから[sptx]、[sbj]、[pymt]、[fwd]、[dat]の 5 つのフィールドを選択し、全てのレコードを[id]の昇順に並べ替えた結果を取得して、新規ブック上のワークシートに複写するプロシージャを Excel マクロ有効ブック上の標準モジュールに作成しようとしている」といった場合であれば、2次元配列に拘らずとも、Excel.Range オブジェクトの CopyFromRecordset メソッドを使用する、といった方法もあるでしょう。

'ファイルパスとテーブル名は適宜書き換えること
Sub Test1()

    Dim strDatabasePath As String
    
    strDatabasePath = "C:\FolderName\FileName.accdb"
    
    If Dir(strDatabasePath) = "" Then
        MsgBox "Access データベースファイル'" & strDatabasePath & "'が見つかりません。", _
               vbExclamation, _
               "ファイル参照エラー"
        Exit Sub
    End If
    
    Dim adoCn As ADODB.Connection
    Dim strConnectString As String
    
    Set adoCn = New ADODB.Connection
    
    With adoCn
        .CursorLocation = adUseClient
        .CommandTimeout = 60
        strConnectString = "Provider=Microsoft.ACE.OLEDB.12.0;Mode=Read;" & _
                           "Data Source=" & strDatabasePath
        Debug.Print strConnectString
        .ConnectionString = strConnectString
        .Open
    End With
    
    Dim adoRs As ADODB.Recordset
    Dim strSQL As String
    
    Set adoRs = New ADODB.Recordset
       
    With adoRs
        Set .ActiveConnection = adoCn
        .CursorLocation = adUseClient
        .CursorType = adOpenStatic
        .LockType = adLockReadOnly
        strSQL = "SELECT t1.[sptx], t1.[sbj], t1.[pymt], t1.[fwd], t1.[dat]" & _
                 " FROM [テーブル名] t1" & _
                 " ORDER BY t1.[id];"
        Debug.Print strSQL
        .Source = strSQL
        .Open
    End With
    
    Dim adoFld As ADODB.Field
    Dim wbkDestination As Excel.Workbook
    Dim wsDestination As Excel.Worksheet
    Dim lngColumn As Long
    
    Set wbkDestination = Workbooks.Add
    Set wsDestination = wbkDestination.Worksheets(1)
    
    wsDestination.Cells(1, 1).Resize(1, adoRs.Fields.Count).NumberFormat = "@"
    For lngColumn = 1 To adoRs.Fields.Count
        Set adoFld = adoRs.Fields(lngColumn - 1)
        wsDestination.Cells(1, lngColumn).Value = adoFld.Name
        Set adoFld = Nothing
    Next
    
    wsDestination.Cells(2, 1).CopyFromRecordset adoRs
    wsDestination.UsedRange.EntireColumn.AutoFit
    
    adoRs.Close
    Set adoRs = Nothing
    adoCn.Close
    Set adoCn = Nothing
    
    Set wsDestination = Nothing
    Set wbkDestination = Nothing

End Sub
7
タークン 2024/01/19 (金) 16:13:24 7a0a1@2705a

hatenaさん、すみませんでした。
連想配列の存在を知らなかったので、読み飛ばしていました。
分からないところが山もり状態ですが、
避けて通るとEXCELに応答していませんと表示されるのを、
数秒間眺めることになるので、なんとか理解します。
放置すると、動かなくなる日は近いはずなので。
ここをクリアしても、また限界が現れると思いますが、
配列周りの処理方法は、次の段階で役立つと思うので、取り組んでみます。

8

前の質問の時もそうでしたが、こちらの質問に対する応答がないですね。
結局、何がしたいのか、何が問題なのか不明のまま議論が深まらずに終了するということになってます。

配列をどうしたいのか、それが不明瞭のままです。これを明確にしてください。

避けて通るとEXCELに応答していませんと表示されるのを、

レコードセットのデータをエクセルに出力するというのが目的でしょうか。
だとしたら、skさんの回答の CopyFromRecordset を使う方法で簡単に実現できます。
連想配列を使う必要もないです。

9
タークン 2024/01/24 (水) 12:17:30 7a0a1@2705a

返信遅れて申し訳ございません。
配列と、連想配列まわりを、ゴニョゴニョやってました。

エクセルのシートを使用しないのが、大きな目的です。
そして、配列と連想配列はすごいです。

キーは重複できないという特性を利用すると、
とんでもない速度で集計できるようになりました。
文字列処理も、連想配列とjoinを使うと負荷が減るようです。

集計と編集をして、カンマ区切りの状態にしてから、
可視で確認するために、最終状態を一気にエクセルシートに張り付けると、
瞬きする間に処理が終了していました。

EXCELは応答していません、と表示されている時間は嘘のようです。

データに間違えが無ければ、エクセルに張り付けずに、
そのまま指定の形式のファイルに出力する方法に変更します。

データがさらに大きくなると、配列に読み込むこと自体に限界が来るようですが、
自己使用の目的だけであれば、VBAは遅いという事は無いと思います。
これを、EXCELと呼べるか微妙ではありますが、とにかくハイパフォーマンスです。

それ以上踏み込むか、とどまるかは目的と趣味の問題ですね。