Excel VBAのCopyFromRecordsetでエラーが出る原因と対処法|7つの確認ポイント

EOFで0件だった転記がMoveFirstの後は2件になる

Excel VBAでCopyFromRecordsetを実行したとき、「データが貼り付けられない」「実行時エラーになる」と困っていませんか? 対処の近道は、思いつきで修正することではなく、接続・Recordset・転記先を順番に切り分けることです。

ケンさん(SE)

たった1行の転記処理なのに、どこを調べればいいの?

チャー

エラー番号と止まった行を確認してから、7つの項目を調べるにゃ。

目次

CopyFromRecordsetで確認すべき7つのポイント

  • 止まった行とエラー番号:接続、SQL、転記のどの段階か。
  • Recordsetの生成:Nothingではないか。
  • Recordsetの状態:ADOならStateが開いている状態か。
  • 現在位置:EOFがTrueになっていないか。
  • 貼り付け先:シート保護・結合セルなどがないか。
  • 転記サイズ:行列数がExcelの範囲を超えないか。
  • フィールド:OLEオブジェクトなど転記できない型が含まれないか。

まずはRecordsetの状態を確認

次のコードはrsを取得済みのADO Recordsetとして、転記直前を診断する抜粋です。接続・SQL実行・後片付けは省略しています。

Dim ws As Worksheet
Dim dest As Range

Set ws = ThisWorkbook.Worksheets("Sheet1")
Set dest = ws.Range("A2")

If rs Is Nothing Then
    MsgBox "Recordsetが設定されていません"
    Exit Sub
End If
If rs.State = 0 Then
    MsgBox "Recordsetが閉じています"
    Exit Sub
End If
If rs.EOF Then
    MsgBox "現在位置に転記対象がありません"
    Exit Sub
End If

dest.CopyFromRecordset rs

ADOとDAOではオブジェクトの状態確認方法が異なります。
また、EOF=Trueは「SQLの検索結果が必ず0件」という意味ではありません。別の処理でRecordsetを最後まで読み進めた場合もTrueになります。

EOF=Trueになった場合の注意点

CopyFromRecordsetはRecordsetの現在位置からデータをコピーします。
先頭に戻すMoveFirstは利用できるカーソルに制限があるため、単純に追加して直るとは限りません。
カーソル設定、直前の読み取り処理、SQLの結果を確認しましょう。

貼り付け先で確認すること

Recordsetの内容が正常でも、シートが保護されている場合や結合セルを含む範囲に書き込む場合は失敗することがあります。検証用の新しいシートを使い、転記範囲の保護や結合を外して切り分けてください。既存データがある場合は上書きにも注意が必要です。

OLE型フィールドがある場合

Microsoftの公式ドキュメントでは、RecordsetにOLEオブジェクトを含むフィールドがあるとCopyFromRecordsetが失敗する、と説明されています。画像などの特殊な列を一緒にSELECTしていないか確認し、必要な列だけをSQLで取り出してみましょう。

【実行前・実行後】EOFがTrueで転記できない例

EOFで0件だった転記がMoveFirstの後は2件になる
Windows版Excelでの実測値をもとにした図解(架空データ)

架空の2件を含むADO Recordsetを末尾まで読み進め、EOF=Trueのまま転記を試すと、戻り値は0でA2は空欄でした。MoveFirstで先頭に戻して転記すると、A2:B3に2件が入りました。

「取得結果はあるはずなのに貼り付けられない」場合を、架空の2件のデータで確認します。1件も出力されない原因が、SQLではなく現在位置にあるケースです。

実行前:Recordsetには2件あるが、読み取り位置が末尾を越えている状態

Recordsetの内容商品名数量
1件目商品A10
2件目商品B20
現在位置EOF=True(次に読むレコードがない)—

次の検証用コードは、外部データベースを使わず、メモリ上に架空のADO Recordsetを作ります。Excelの標準モジュールに貼り付けてください。Windows版ExcelでADOを利用できる環境を想定し、遅延バインディングを使っています。

Sub DemoEOFAndCopyFromRecordset()
    Dim rs As Object, ws As Worksheet
    Dim dest As Range
    Set ws = ThisWorkbook.Worksheets.Add
    Set rs = CreateObject("ADODB.Recordset")

    rs.CursorLocation = 3  ' adUseClient
    rs.Fields.Append "商品名", 202, 30  ' adVarWChar
    rs.Fields.Append "数量", 3          ' adInteger
    rs.Open
    rs.AddNew Array("商品名", "数量"), Array("商品A", 10)
    rs.AddNew Array("商品名", "数量"), Array("商品B", 20)
    rs.MoveFirst

    ' 全件を読み進めてEOF=Trueを再現
    Do Until rs.EOF
        rs.MoveNext
    Loop
    Debug.Print "転記前 EOF=" & rs.EOF  ' True

    ' 静的カーソルを使用した検証例:先頭へ戻す
    rs.MoveFirst
    ws.Range("A1").Value = "商品名"
    ws.Range("B1").Value = "数量"
    Set dest = ws.Range("A2")
    dest.CopyFromRecordset rs

    rs.Close
    Set rs = Nothing
End Sub

実行後:新規ワークシートに2件が出力される

Excelの行A列:商品名B列:数量
1商品名数量
2商品A10
3商品B20

ここでのMoveFirstは、先頭に戻れるRecordsetを意図的に作った検証例です。実際のシステムで前方専用カーソルを使っている場合は利用できないことがあるため、むやみに追加せず、カーソル設定やSQLの再実行を確認しましょう。

検証環境はWindows版Excel 16.0(ビルド20527)とADOです。2026年11月8日に、外部データベースを使わず架空データで検証しました。

CopyFromRecordsetをもっと詳しく学びたい方へ

基本操作からエラー対策、データの取り込みや書式設定まで体系的に学びたい方には、Kindle書籍『Excel VBA CopyFromRecordset 実践ガイド』もおすすめです。

チャー

ぜひ、読んでみてニャ🐈

まとめ

大切なのはエラー発生行→Recordsetの状態→現在位置→転記先の順に調べること。
一度に複数箇所を変更せず、検証結果を残すと原因を特定しやすくなります。

関連記事・もっと詳しく学ぶには

基本から確認したい方は、CopyFromRecordsetの使い方完全ガイドをご覧ください。
高速化の背景はCopyFromRecordsetはなぜ速い?で解説しています。

参考資料:Microsoft Learn:Range.CopyFromRecordset メソッド(確認日:2026年11月8日)。コード例は架空データ・一般的な環境を想定しています。本番実行前に検証してください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次