VBA技術解説
ADO(ActiveX Data Objects)の使い方の要点

ExcelマクロVBAの問題点と解決策、VBAの技術的解説
最終更新日:2020-01-21

ADO(ActiveX Data Objects)の使い方の要点


ADOはMicrosoftが提供するデータベースアクセスのためのソフトウェア部品です。
OLE DBをActiveXコントロールの形で使えるようにしたプログラミングインターフェースになります。
ここでは、ADOを使用したデータベースへの接続方法を解説します。


扱えるデータベースに特段の制限はありません。
対応するドライバーや、プロバイダが使用可能であれば、どんなDBでも扱えます。

データベースの種類

本ページで接続礼として記載するデータベースは、

CSV
Excel
Access
MySql
SQLServer
Oracle

以上になります。
CSVもExcelもデータベースとして扱えます。
ただし、データがデータベース形式になっていることが前提です。
(各列に見出しがあり、列見出しの下に1行1件のデータが並んでいること)

SQL(SQL:Structured Query Language)

ADOには、
レコードの追加・削除・検索・抽出・並べ替えなどの基本的な操作が用意されています。
この操作を記述するのが、SQL文です。
VBAでのSQLの基礎(SQL:Structured Query Language)
SQL(StructuredQueryLanguage:構造化問い合わせ言語)は、データベースの定義や表の操作を行う言語です。データ定義言語であるDDL(datadescriptionlanguage)と データ操作言語であるDML(datamanipulationlanguage)に分けられます。

SQL文を書くことで、
複数のテーブルから、必要なデータセットを自由に抽出、また更新、追加する事ができます。

新シリーズ「SQL入門」を開始しました。
社会的にパソコンで扱うデータ量は近年急激に増えています。これに呼応してエクセルも2003までは65536行まででしたが、2007から飛躍的に増えて1048576行となっています。しかしエクセルで100万行扱えるといっても、データ量としては列数もありますので、実際には100万行はおろか数十万行でもエクセルが重くなって扱いづらくなってしまいます。
より詳しくSQLについて解説しています。

ADOを使う準備

VBE(VBAの編集画面)で、
ツール→参照
ここで、
Microsoft ActiveX Data Objects 2.X Library
または
Microsoft ActiveX Data Objects 6.1 Library
を追加して下さい。
オブジェクトのバージョンは各種ありますが、現在なら2.8が無難でしょうか。
このように、事前に参照設定することを、事前バインディングとして、

事前に参照設定をしない方法もあります。
CreateObject関数を使います。
この方法は、
実行時バインディングまたは遅延バインディングといいます。
参照設定、CreateObject、オブジェクト式の一覧
VBAでエクセル外のオブジェクトを使うときには、事前バインディングと遅延バインディング(実行時バインディング)の2通りがあります、この時それぞれ何を指定したらよいのか、指定する文字列が長いので結構探してしまうことが度々あります。そこで、自身の覚え書きとしての意味も含めて、参照設定、CreateObjectのclass、

基本的には、事前バインディングを使ってマクロを作成します。
入力候補に、オブシェクトのメンバーが表示されますので、マクロを書く際に役に立ちます。

以下では、DBごとにサンプルコードを掲載します。
自身の備忘録も兼ねています。

ADOでのDB接続方法

CSV

Sub ReadCsv()
  Dim objCn As New ADODB.Connection
  Dim objRS As ADODB.Recordset
  Dim strSQL As String

  'コネクション
  With objCn
    .Provider = "Microsoft.ACE.OLEDB.12.0"
    .Properties("Extended Properties") = "Text;HDR=NO"
    .Open ThisWorkbook.Path & "\"
  End With
  
  'SQL作成
  strSQL = ""
  strSQL = strSQL & " SELECT *"
  strSQL = strSQL & " FROM"
  strSQL = strSQL & " CSVTEST.csv"
  
  '接続
  Set objRS = New ADODB.Recordset
  Set objRS = objCn.Execute(strSQL)
  
  'レコードセットをシート出力
  With Worksheets("出力シート")
    .UsedRange.ClearContents
    .Range("A1").CopyFromRecordset objRS
  End With
  
  '切断
  objCn.Close
  Set objRS = Nothing
  Set objCn = Nothing
End Sub

以下、
With objCn
  この部分の違いだけですので、ここだけを掲載します。
End With


Excel

With objCn
  .Provider = "Microsoft.ACE.OLEDB.12.0"
  .Properties("Extended Properties") = "Excel 12.0"
  .Open ThisWorkbook.Path & "\TEST.xlsx"
End With

Access

Dim strDb As String
strDB = ThisWorkbook.Path & "\sample.accdb"
With objCn
  .ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strDB
  .Open
End With

ここからは、
.ConnectionStringに入れる文字列の違いになります。

MySql

"Driver={MySQL ODBC 5.1 DRIVER}; SERVER=サーバー名(またはIPアドレス); DATABASE=DB名; USER=ユーザーID; PASSWORD=パスワード;"

ドライバーは、
"MySQL ODBC 3.51 DRIVER"
"MySQL ODBC 4.1 DRIVER"
"MySQL ODBC 4.2 DRIVER"
"MySQL ODBC 5.1 DRIVER"
"MySQL ODBC 5.2 DRIVER"
"MySQL ODBC 5.3 DRIVER"
等、PCにインストールされているドライバーを指定します。

SQLServer

"Provider=SQLOLEDB;Data Source=サーバー名(またはIPアドレス);Initial Catalog=DB名;user id=ユーザーID;password=パスワード"

Oracle

"Provider=OraOLEDB.Oracle;Data Source=リスナー名;User ID=ユーザーID;Password=パスワード;"

オラクルの場合は、Oracleクライアントのインストールが必要です。
そして、リスナーの登録をしておいて下さい。

ODBCを使う場合

DBに依存しない方法としては、ODBCを使う事も出来ます。

"DSN=ODBC名;UID=ユーザーID;PWD=パスワード;"

ODBCを事前に作成しておきますが、ODBCの32bitと64bitに注意してください。
※OSが64bitのコントロールパネルにあるODBCは64bit用です。
32bit用の設定は、C:\Windows\SysWOW64\odbcad32.exe
VBAで使用する場合は、32bit用のODBCを使用した方がやりやすいかもしれません。
もちろん64bitでも問題ありません。
ODBC用のドライバーとbit数を合わせて使ってください。

ADODB.Recordsetの取得方法

ADODB.ConnectionのExecuteメソッド

最初のサンプルVBAで使っている方法です。

Set recordset = connection.Execute (CommandText, RecordsAffected, Options)

CommandText
実行する SQL文字列の値です。
RecordsAffected
省略可能です。
この操作の影響を受けたレコード数をプロバイダーが返す長整数型 ( Long ) の値です。
Options
省略可能です。
MoveRecordOptionsEnum値を指定します。
プロバイダーが CommandText引数を評価する方法を示す長整数型 (Long) の値です。
1つまたは複数のCommandTypeEnum値またはExecuteOptionEnum値のビットマスクを指定できます。
CommandTypeEnum
定数 説明
adcmdunspecified -1 コマンドの種類の引数を指定しません。
adcmdtext 1 CommandTextを、コマンドまたはストアド プロシージャのテキスト定義として評価します。
adcmdtable 2 CommandTextを、内部的に生成された SQL クエリから返された列のみで構成されるテーブル名として評価します。
adCmdStoredProc 4 CommandTextをストアド プロシージャ名として評価します。
adcmdunknown 8 既定値。
CommandTextプロパティのコマンドの種類が不明であることを示します。
adCmdFile 256 CommandTextを、保存されたRecordsetのファイル名として評価します。Recordset.OpenまたはRequeryと組み合わせてのみ使用できます。
adCmdTableDirect 512 CommandTextを、すべての列が返されたテーブル名として評価します。
Recordset.OpenまたはRequeryと組み合わせてのみ使用できます。
Seekメソッドを使用する場合、RecordsetはadCmdTableDirectを指定して開く必要があります。
この値は、ExecuteOptionEnumの値adAsyncExecuteと組み合わせて使用できません。

ExecuteOptionEnum
定数 説明
adAsyncExecute 0x10 コマンドを非同期に実行することを示します。
この値は、CommandTypeEnumの値adCmdTableDirectと組み合わせて使用できません。
adAsyncFetch 0x20 CacheSizeプロパティで指定した初期量の残りの行を非同期に取得することを示します。
adAsyncFetchNonBlocking 0x40 取得中にメイン スレッドがブロックしないことを示します。
要求された行がまだ取得されていない場合、現在の行が自動的にファイルの最後に移動します。
永続的に保存されたRecordsetを持つStreamからRecordsetを開いた場合、adAsyncFetchNonBlockingは無効になり、操作は同期で実行され、ブロッキングが発生します。
adCmdTableDirectオプションを使用してRecordsetを開いた場合、adAsynchFetchNonBlockingは無効になります。
adExecuteNoRecords 0x80 コマンド テキストが、行を返さないコマンドまたはストアド プロシージャ (たとえば、データの挿入のみを行うコマンド) であることを示します。
取得した行があっても削除されるので、コマンドからは返されません。
adExecuteNoRecordsは、コマンドまたはConnectionのExecuteメソッドに、省略可能なパラメーターとしてのみ渡すことができます。
adExecuteStream 0x400 コマンドの実行結果がストリームとして返されることを示します。
adExecuteStreamは、CommandExecuteメソッドにオプションのパラメーターとして渡すことができます。
adExecuteRecord CommandTextが、Recordオブジェクトとして返される単一の行を返すコマンドまたはストアド プロシージャであることを示します。
adoptionunspecified -1 コマンドが指定されていないことを示します。

内部処理を最小限に抑えてパフォーマンスを向上させるには、ExecuteOptionEnumの値adExecuteNoRecords を使用します。
Executeでは、CommandTypeEnumの値 dCmdFileまたはadCmdTableDirectを使用しないでください。 これらの値は、RecordsetのOpenメソッドおよびRequeryメソッドのオプションとしてのみ使用できます。

ADODB.ConnectionのExecuteの使用例
Dim objCn As New ADODB.Connection
Dim objRS As ADODB.Recordset
'コネクション
'SQL作成
Set objRS = New ADODB.Recordset
Set objRS = objCn.Execute("SQL文字列")

ADODB.RecordsetのOpenメソッド

recordset.Open Source, ActiveConnection, CursorType, LockType, Options

Source
オプション。
有効なCommandオブジェクト、SQLステートメント、テーブル名、ストアドプロシージャコール、URL、または永続的に保存されたRecordsetを含むファイルまたはStreamオブジェクトの名前に評価されるVariant。
ActiveConnection
オプション。
有効なConnectionオブジェクト変数名に評価されるVariant、またはConnectionStringパラメーターを含むStringのいずれか。
CursorType
オプション。
Recordsetを開くときにプロバイダーが使用するカーソルのタイプを決定するCursorTypeEnum値。
デフォルト値はadOpenForwardOnlyです。

定数 Value 説明
adOpenDynamic 2 動的カーソルを使用します。
他のユーザーによる追加、変更、削除が表示され、プロバイダーがサポートしていない場合、ブックマークを除き、Recordsetを介したすべてのタイプの移動が許可されます。
adOpenForwardOnly 0 デフォルト。
順方向専用カーソルを使用します。
レコードを順方向にしかスクロールできないことを除いて、静的カーソルと同じです。
これにより、レコードセットを1回だけ通過する必要がある場合のパフォーマンスが向上します。
adOpenKeyset 1 キーセットカーソルを使用します。
動的カーソルに似ていますが、他のユーザーが追加したレコードは表示できませんが、他のユーザーが削除したレコードにはレコードセットからアクセスできません。
他のユーザーによるデータの変更は引き続き表示されます。
adOpenStatic 3 静的カーソルを使用します。
静的カーソルは、データの検索またはレポートの生成に使用できる一連のレコードの静的コピーです。
他のユーザーによる追加、変更、または削除は表示されません。
adOpenUnspecified -1 カーソルの種類を指定しません。

LockType
オプション。
Recordsetを開くときにプロバイダーが使用するロックの種類(同時実行性)を決定するLockTypeEnum値。
デフォルト値はadLockReadOnlyです。

Constant Value Description
adLockBatchOptimistic 4 楽観的なバッチ更新を示します。
バッチ更新モードに必要です。
adLockOptimistic 3 レコードごとに楽観的ロックを示します。
プロバイダーは楽観的ロックを使用し、Updateメソッドを呼び出すときにのみレコードをロックします。
adLockPessimistic 2 レコードごとに悲観的ロックを示します。
プロバイダーは、通常、編集直後にデータソースでレコードをロックすることにより、レコードの正常な編集を保証するために必要なことを行います。
adLockReadOnly 1 読み取り専用レコードを示します。
データを変更することはできません。
adLockUnspecified -1 ロックのタイプを指定しません。
クローンの場合、クローンはオリジナルと同じロックタイプで作成されます。

Options
オプション。
Commandオブジェクト以外のものを表す場合、または以前に保存されたファイルからRecordsetを復元する必要がある場合、プロバイダがSource引数を評価する方法を示すLong値。
1つ以上のCommandTypeEnum値またはExecuteOptionEnum値を指定できます。
これらの値は、ビット単位のOR演算子と組み合わせることができます。
※CommandTypeEnum値およびExecuteOptionEnum値については、ConnectionのExecuteに記載してあります。

ADODB.RecordsetのOpenメソッドの使用例
Dim objCn As New ADODB.Connection
Dim objRS As ADODB.Recordset
'コネクション接続する
'SQL作成する
Set objRS = New ADODB.Recordset
Call objRS.Open("SQL文字列", objCn, adOpenStatic, adLockReadOnly)

ADODBのレコードセットの扱い方

ADODBのレコードセットには多くのメソッドがあります。
以下は良く使う代表的なメソッド・プロパィについての使用例になります。

Recordsetを開くと、現在のレコードは最初のレコード(存在する場合)に配置され、BOFプロパティとEOFプロパティはFalseに設定されます。
レコードがない場合、BOFおよびEOFプロパティ設定はTrueです。

指定されたRecordsetオブジェクトの最初(MoveFirst)、最後(MoveLast)、次(MoveNext)、または前(MovePrevious)のレコードに移動し、そのレコードを現在のレコードにします。

Recordsetのシートへの一括出力

Dim objCn As New ADODB.Connection
Dim objRS As ADODB.Recordset
'コネクション接続する
'SQL作成する
Set objRS = New ADODB.Recordset
Call objRS.Open("SQL文字列", objCn, adOpenStatic, adLockReadOnly)
With Worksheets("出力シート")
  .UsedRange.ClearContents
  .Range("A1").CopyFromRecordset objRS
End With

RangeオブジェクトのCopyFromRecortsetメソッドを使用します。

CopyFromRecortsetメソッド

指定された範囲の左上隅を始点として、Recordsetオブジェクトの内容をワークシートにコピーします。

Rangeオブジェクト.Copyfromrecordset(Data、 MaxRows、 MaxColumns)

名前 説明
Data 必須です。
セル範囲にコピーするRecordsetオブジェクトを指定します。
MaxRows 省略可能です。
ワークシートにコピーするレコードの最大数を指定します。
この引数を省略すると、Recordset?オブジェクトのすべてのレコードをコピーします。
MaxColumns 省略可能です。
ワークシートにコピーするフィールドの最大数を指定します。
この引数を省略すると、Recordsetオブジェクトのすべてのフィールドをコピーします。

Recordsetオブジェクトのカレント レコードの位置からコピーが行われます。
コピーが完了すると、Recordset オブジェクトのEOFプロパティはTrueになります。

Recordsetの取得件数

Dim objCn As New ADODB.Connection
Dim objRS As ADODB.Recordset
'コネクション接続する
'SQL作成する
Set objRS = New ADODB.Recordset
Call objRS.Open("SQL文字列", objCn, adOpenStatic, adLockReadOnly)
If objRS.RecordCount <= 0 Then
  MsgBox "レコードなし"
End If

RecordCountで件数を取得する場合は、adOpenStaticを指定しRecordCountで取得します。

カラム名の取得

Dim i As Long
'カラム名の出力
For i = 0 To objRS.Fields.Count - 1
  Cells(1, i + 1) = objRS.Fields(i).Name
Next

Fieldsコレクションの要素を指定してFieldオブジェクトを特定し、Nameプロパティで取得します。

レコードセットの全件順処理

Dim i As Long, j As Long
i = 2
objRS.MoveFirst 'ここでは不要だが参考として
Do Until objRS.EOF
  For j = 0 To objRS.Fields.Count - 1
    Cells(i, j + 1) = objRS(j).Value
  Next
  objRS.MoveNext
  i = i + 1
Loop

EOFプロパティがTrueになるまで、MoveNextでカレントレコードを次に進めていきます。

レコードの検索/追加/更新/削除

レコードの検索
recordset.Find (Criteria、 SkipRows、 searchdirection、 Start)

adsearchbackward -1 後方検索をし、Recordset?の先頭で終了します。一致するレコードが見つからない場合、レコード ポインターは?BOF?に移動します。
adsearchforward 1-d 前方検索をし、Recordset?の末尾で終了します。一致するレコードが見つからない場合、レコード ポインターは?EOF?に移動します。

レコードの追加
recordset.AddNew FieldList, Values
FieldListおよびValuesは、配列を指定します。

レコードの更新
recordset.Update FieldList, Values
FieldListおよびValuesは、配列を指定します。
カレント行が更新されますので、事前に対象レコードに移動しておきます。

レコードの削除
recordset.Delete
カレント行が削除されますので、事前に対象レコードに移動しておきます。

検索/追加/更新/削除の使用例
With objRS
  '追加
  .AddNew Array("列1", "列2"), Array("値1", "値2")

  '更新
  .MoveFirst
  .Find "列1 = 値1", 0, adSearchForward
  .Update Array("列1", "列2"), Array("値1", "値2")

  '削除
  .MoveFirst
  .Find "列2 = 値2", 0, adSearchForward
  .Delete
End With

ADODBのトランザクション処理

ADODBでトランザクション処理を行うには、ADODB.Connectionオブジェクトのメソッドを使用します。

BeginTrans メソッド
CommitTrans メソッド
RollbackTrans メソッド

各DBのプロバイダーによっては、入れ子になったトランザクションをサポートしています。
BeginTransでトランザクションを開始した後、CommitTransすることなくDBをクローズした場合はロールバックされます。
トランザクションの更新内容は、CommitTransしない限り確定されることはありません。

トランザクション処理の詳細については、以下を参照してください。
トランザクション処理|SQL入門
エクセルVBAでデータベースを扱うためのSQL入門です。前回までは、1つのテーブルにデータを追加/更新/削除してきました。システム構築していく上では、複数のテーブルへの処理は必要不可欠になります。しかし、このとき注意しなければならない問題があります。

ADODB.Commandの使い方

ADOにはCommandオブジェクトがあり、パラメーター方式でSQLを実行できます。

AdoCmd = New ADODB.Command
Set AdoCmd.ActiveConnection = 接続済コネンション
AdoCmd.CommandText = SQL文字列 '(?,?,?)
AdoCmd.Execute Parameters:=値リスト1 '(値1,値2,値3)
'・・・
AdoCmd.Execute Parameters:=値リスト2 '(値4,値5,値6)

SQL文字列中の「?」に対して値リストを順番に適用します。
同じSQLを実行する場合は、データだけをパラメーターとして渡すので効率的です。

以下で具体的に使用しています。
データの挿入(INSERT)と全削除|SQL入門
エクセルVBAでデータベースを扱うためのSQL入門です。前回までにテーブルを自由に作れるようになり、ワークシートからの自動作成も出来上がりました。今回は作成したテーブルにデータを追加(INSERT)していきます。

最後に注意点等

接続文字列等では大文字小文字が混在していますが、大文字小文字は区別されませんので問題ありません。
最後の;については、あっても無くても動きますが、書いておいた方が良いと思います。

全体を通しての注意点としては、
データに、'シングルクォーテーションを含む場合は、
それをエスケープするために、'シングルクォーテーションを2個重ねるようにします。

データを更新・追加する場合は、nullに注意してください。
Excelの空欄セルをデータとして使う時に、0バイト文字なのかnullなのか、DB仕様と合わせて記述に気を付けます。

更新・追加する場合は、トランザクション処理は必須だとお考え下さい。
さらにデータが多い時は、マルチプルインサートにすることも考えましょう。
これをバルクインサートという言い方もします、ただしDBによって構文がそれぞれ違ってきます。
またDBによりますが、
大抵はCSVから直接ロードする命令が用意されていて、これを使うとかなり高速で全件処理が可能ですので検討してみましょう。



同じテーマ「マクロVBA技術解説」の記事

VBAでのInternetExplorer自動操作
VBAでのSQLの基礎(SQL:Structured Query Language)
VBAで正規表現を利用する(RegExp)
VBAでメール送信する(CDO:Microsoft Collaboration Data Objects)
VBAでのOutlook自動操作
ADO(ActiveX Data Objects)の使い方の要点
特殊フォルダの取得(WScript.Shell,SpecialFolders)
参照設定、CreateObject、オブジェクト式の一覧
VBAのスクレイピングを簡単楽にしてくれるSelenium
VBA+SeleniumBasicで検索順位チェッカー作成
VBA+SeleniumBasicで検索順位チェッカー(改)


新着記事NEW ・・・新着記事一覧を見る

VBA100本ノック 37本目:グラフの色設定|VBA練習問題(12月1日)
VBA100本ノック 36本目:列の並べ替え|VBA練習問題(12月1日)
VBA100本ノック 35本目:条件付き書式|VBA練習問題(11月29日)
VBA100本ノック 34本目:配列の左右回転|VBA練習問題(11月28日)
VBA100本ノック 33本目:マクロ記録の改修|VBA練習問題(11月26日)
VBA100本ノック 32本目:Excel終了とテキストファイル出力|VBA練習問題(11月25日)
VBA100本ノック 31本目:入力規則|VBA練習問題(11月24日)
将棋とプログラミングについて~そこには型がある~|エクセル雑感(11月22日)
VBA100本ノック 30本目:名札作成(段組み)|VBA練習問題(11月22日)
VBA100本ノック 29本目:画像の挿入|VBA練習問題(11月21日)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.RangeとCellsの使い方|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
5.マクロって何?VBAって何?|VBA入門
6.繰り返し処理(For Next)|VBA入門
7.Range以外の指定方法(Cells,Rows,Columns)|VBA入門
8.セルに文字を入れるとは(Range,Value)|VBA入門
9.とにかく書いてみよう(Sub,End Sub)|VBA入門
10.マクロはどこに書くの(VBEの起動)|VBA入門




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。



このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ