【入門編】ADOのRecordsetをJSON形式に変換する:Web API連携を見据えたデータ構造の変換術 – Access VBA解析バイブル

スポンサーリンク
スポンサーリンク

Access VBAを現代の武器へ:ADO RecordsetをJSONへ変換し、Web APIの世界へ漕ぎ出す

こんにちは。現場で数々のシステム崩壊と再生を繰り返してきた、あなたの先輩エンジニアです。

「Accessは、自分ひとりで使う表計算ソフトの延長だ」……もしあなたがそう思っているとしたら、少しだけもったいないかもしれません。Access VBAの真の力は、「閉じたローカル環境のデータを、外部の広大なWeb世界と繋ぐ架け橋(ブリッジ)になること」にあります。

今日は、マクロの記録から一歩踏み出し、「プログラムによるデータの構造化」という、エンジニアとして非常に重要なステップに挑戦しましょう。テーマは「ADOのRecordsetをJSON形式に変換する」です。

ここをクリアすれば、あなたのAccessは、最新のWebサービスやAI(ChatGPT APIなど)と対話できる「現代的なアプリケーション」へと進化しますよ。さあ、一緒に見ていきましょう。

1. なぜ「DAO」ではなく「ADO」なのか? アーキテクチャの選択

まず、設計(アーキテクチャ)の観点から重要な話をします。Accessでデータを扱う際、皆さんはおそらく`DAO`(Data Access Objects)を使い慣れているでしょう。Accessのテーブルを操作するなら、DAOは最高に高速で最適化されています。

しかし、今回のように「外部システム(Web API)との連携」を見据えるなら、`ADO`(ActiveX Data Objects)を選択するのが定石です。

違いを直感的に理解しよう

特徴 DAO (Data Access Objects) ADO (ActiveX Data Objects)
得意分野 Access内部のテーブル操作 外部データベースやネットワーク越しへの接続
設計思想 Accessエンジンに特化 汎用的(SQL Server, Oracle, Web等へも対応)
今回の用途 ローカルの高速処理 Web APIへ渡すためのデータ加工

Web APIの世界では、データは「行と列」の形式ではなく、「JSON(JavaScript Object Notation)」という、テキストベースの構造化された形式でやり取りされます。ADOを使ってデータを取得し、それをJSONという「共通言語」に翻訳してあげる。これが、現代的な連携の第一歩です。

2. JSONへの変換:シリアライズという概念

「RecordsetをJSONにする」という作業を、プロの世界では「シリアライズ(直列化)」と呼びます。

イメージしてください。

  • Recordsetは、メモリ上に浮かんでいる「立体的なデータの塊(オブジェクト)」です。そのままでは、インターネットの細いケーブルを通って外へは出られません。
  • JSONは、ただの「一本の長い文字列(テキスト)」です。これなら、どんな通信経路でもスムーズに流れていきます。

この「立体的なオブジェクト」を「一本の文字列」に解体して並べ替える作業こそが、今回私たちが実装するコードの正体です。

3. 実装コード:RecordsetをJSON文字列へ変換する

それでは、魂を込めたコードを見ていきましょう。このコードは、複雑なライブラリを使わず、VBAの基本機能だけで「Recordsetの構造を解析してJSONを作る」ロジックを組み上げています。

事前準備

VBAエディタのメニューから [ツール] -> [参照設定] を開き、「Microsoft ActiveX Data Objects x.x Library」にチェックを入れておいてください。

Option Compare Database
Option Explicit

''' <summary>
''' ADO RecordsetをJSON形式の文字列に変換する関数
''' </summary>
''' <param name="rs">変換対象のADO Recordsetオブジェクト</param>
''' <returns>JSON形式の文字列</returns>
Public Function RecordsetToJSON(ByRef rs As ADODB.Recordset) As String
    Dim json As String
    Dim fld As ADODB.Field
    Dim isFirstRecord As Boolean
    Dim isFirstField As Boolean
    
    ' Recordsetが空、または閉じている場合のガード
    If rs Is Nothing Then Exit Function
    If rs.State = adStateClosed Then Exit Function
    If rs.EOF And rs.BOF Then
        RecordsetToJSON = "[]" ' 空の配列を返す
        Exit Function
    End If

    ' JSONの開始(配列の開始)
    json = "["
    isFirstRecord = True

    ' --- レコードのループ処理 ---
    Do While Not rs.EOF
        ' 2件目以降のレコードの前にはカンマを入れる
        If Not isFirstRecord Then
            json = json & ","
        End If
        
        ' レコードオブジェクトの開始
        json = json & "{"
        isFirstField = True
        
        ' --- フィールド(列)のループ処理 ---
        For Each fld In rs.Fields
            ' フィールドの区切りとしてカンマを入れる
            If Not isFirstField Then
                json = json & ","
            End If
            
            ' JSONの「"キー": 値」の形式を作成
            ' キー(フィールド名)は必ずダブルクォーテーションで囲む
            json = json & """" & fld.Name & """:"
            
            ' 値の型に応じた処理(ここがプロの腕の見せ所)
            Select Case fld.Type
                Case adInteger, adSmallInt, adTinyInt, adBigInt, adSingle, adDouble, adDecimal, adCurrency
                    ' 数値型はそのまま
                    json = json & fld.Value
                    
                Case adBoolean
                    ' 真偽値は true/false (小文字)
                    json = json & IIf(fld.Value, "true", "false")
                    
                Case adDate
                    ' 日付型は文字列としてダブルクォーテーションで囲む
                    json = json & """" & Format(fld.Value, "yyyy-mm-ddThh:mm:ss") & """"
                    
                Case Else
                    ' 文字列やNull、その他はダブルクォーテーションで囲む
                    ' Null対策として、Nullの場合は null という文字列を入れる
                    If IsNull(fld.Value) Then
                        json = json & "null"
                    Else
                        ' 文字列内のダブルクォーテーションをエスケープ(重要!)
                        json = json & """" & Replace(fld.Value, """", "\""") & """"
                    End If
            End Select
            
            isFirstField = False
        Next fld
        
        ' レコードオブジェクトの終了
        json = json & "}"
        
        isFirstRecord = False
        rs.MoveNext
    Loop

    ' JSONの終了(配列の終了)
    json = json & "]"
    
    RecordsetToJSON = json
End Function

''' <summary>
''' テスト実行用プロシージャ
''' </summary>
Public Sub TestJSONConversion()
    Dim conn As ADODB.Connection
    Dim rs As ADODB.Recordset
    Dim strJSON As String
    
    ' 1. 接続のセットアップ(ここでは現在のAccessデータベースに接続)
    Set conn = New ADODB.Connection
    conn.Open CurrentProject.Connection
    
    ' 2. テスト用のRecordsetを作成(実際はSQLで取得してください)
    Set rs = New ADODB.Recordset
    ' ※テスト用に、既存のテーブル「T_Sample」がある前提のSQLです
    ' もしテーブルがない場合は、適宜書き換えてください
    rs.Open "SELECT ID, UserName, Age, IsActive, JoinDate FROM T_Sample", conn, adOpenStatic, adLockReadOnly
    
    ' 3. 変換実行
    strJSON = RecordsetToJSON(rs)
    
    ' 4. 結果表示
    Debug.Print "--- 生成されたJSON ---"
    Debug.Print strJSON
    MsgBox "JSONの生成が完了しました。イミディエイトウィンドウを確認してください。"

    ' 5. 後始末(オブジェクトのライフサイクル管理)
    rs.Close
    conn.Close
    Set rs = Nothing
    Set conn = Nothing
End Sub

4. ここが落とし穴!陥りやすいエラーと回避術

コードを書いた後に「動かない!」と頭を抱えないために、私が現場で見てきた「よくある失敗」を伝授します。

① Null(空っぽ)の恐怖

VBAの`Null`をそのまま文字列結合しようとすると、エラーになったり、意図しない挙動をしたりします。JSONの世界では、値がないことは `”null”` という文字列(あるいは `null` というリテラル)で表現する必要があります。上記のコードでは、`If IsNull(fld.Value)` でしっかりと対策しています。

② 末尾のカンマ問題

初心者が最も陥りやすいのが、「JSONの最後の要素の後にカンマが残ってしまう」エラーです。
`[{“id”:1}, {“id”:2},]` ← この最後のカンマがあるだけで、Web APIは「壊れたデータだ!」と怒って拒絶します。
今回のコードでは、`isFirstRecord` や `isFirstField` というフラグを使って、「最初の一回目以外は、前にカンマを置く」というロジックにしています。これで綺麗に解決できます。

③ オブジェクトのライフサイクル(後始末)

`Recordset` や `Connection` は、使い終わったら必ず `.Close` し、`Set … = Nothing` で解放してください。これを怠ると、メモリリーク(メモリの無駄遣い)が発生し、Accessが突然重くなったり、強制終了したりする原因になります。「使い終わったら、きれいに片付ける」。これは一流のエンジニアの鉄則です。

まとめ:一歩ずつ、確実に

いかがでしたか?
Recordsetをループで回し、型を判定し、文字列を組み立てていく……一見すると泥臭い作業に見えるかもしれません。しかし、この「データの構造を理解して作り替える」というプロセスこそが、プログラミングの醍醐味です。

これができるようになれば、あなたはもう単なる「マクロ使い」ではありません。「データをコントロールし、外部の世界へ繋ぐことができるエンジニア」への第一歩を踏み出したのです。

大丈夫、最初は難しく感じても、何度もコードに触れるうちに、必ず手が覚えていきます。もしエラーが出ても、それは成長のチャンスです。

ここをクリアすれば、Access VBAの基本はバッチリですよ。応援しています!

タイトルとURLをコピーしました