ADOでAccess・Excel・CSVへ接続・操作
- MSDASQLプロバイダー編 -
- 1.データベースへの接続方法
- 2.ODBCについて
- 2-1.ODBCドライバー
- 2-2.DSN
- よりみち(DSNの名前)
- 2-2-1.AccessのDSN
- 2-2-2.ExcelのDSN
- 2-2-3.テキスト(CSV)のDSN
- よりみち(テキストの列情報の編集)
- 3.ADOのオブジェクトについて
- 3ー1.ADOオブジェクトの種類
- 3ー2.ADOオブジェクト生成
- 3ー2ー1.事前バインディング
- 3ー2ー2.実行時バインディング
- 4.Connectionオブジェクト
- 4ー1.Openメソッド他(データベース接続関係)
- 4ー1ー1.第1パラメータ(ConnectionString:接続情報)
- 4ー1ー1ー1.プロバイダー名
- 4ー1ー1ー2.ドライバー名
- 4ー1ー1ー3.データベース名
- よりみち(テーブル名)
- 4ー1ー1ー4.DSN名
- 4ー1ー1ー5.ユーザー名、パスワード
- 4ー1ー1ー6.URL名
- 4ー1ー1ー7.読取/書込
- よりみち(Modeプロパティ)
- よりみち(HDRなどの設定)
- 4ー1ー2.第2・第3パラメータ(UserID、Password)
- 4ー1ー3.第4パラメータ(Options:同期/非同期)
- 4ー1ー4.データベース接続までのコード例
- 4ー2.Executeメソッド(コマンドの実行)
- 5.Recordsetオブジェクト
- 5ー1.Openメソッド(レコードセット取得)
- 5ー1ー1.各パラメータの値
- 5ー1ー2.各パラメータの組み合わせ
- 5ー1ー2ー1.Accessの場合(Openメソッドにはテーブル名を指定)
- よりみち(CursorType=adOpenForwardOnlyでの不具合)
- 5ー1ー2ー2.Accessの場合(OpenメソッドにはSQL文を指定)
- 5ー1ー2ー3.ExcelシートDBの場合(OpenメソッドにはSQL文を指定)
- 5ー1ー2ー4.CSVの場合(OpenメソッドにはSQL文を指定)
- 6.Commandオブジェクト
- 6ー1.ActiveConnectionプロパティ(データベースとの結び付け)
- 6ー2.CommandTextプロパティ(実行コマンドの格納)
- 6ー3.Executeメソッド(コマンドの実行)
- よりみち(Optionsパラメータの指定方法)
- 6ー4.Commandオブジェクトの使用例
- 6ー4ー1.実行コマンドの格納
- 6ー4ー2.コマンドの実行
- 7.データベースに接続する為のコード例
- 7ー1.テーブルを操作
- 7ー1ー1.Connectionでテーブル名を実行し、レコードセット取得後に処理
- 7ー1ー2.Commandでテーブル名を実行し、レコードセット取得後に処理
- 7ー1ー3.Commandにテーブル名を格納後Recordset実行し、レコードセット取得後に処理
- 7ー1ー4.Recordsetでテーブル名を実行し、レコードセット取得後に処理
- 7ー2.SQL(Select)文で操作
- 7ー2ー1.ConnectionでSQL文を実行しレコードセット取得
- 7ー2ー2.CommandでSQL文を実行しレコードセット取得
- 7ー2ー3.CommandにSQL文を格納後Recordsetで取得
- 7ー2ー4.Recordsetに直接SQL文を指定しレコードセット取得
- 7ー3.SQL(Insert等)文で操作
- 7ー3ー1.ConnectionでSQL文を実行しデータ変更
- 7ー3ー2.CommandでSQL文を実行しデータ変更
- 7ー3ー3.CommandにSQL文を格納後Recordsetで実行しデータ変更
- 7ー3ー4.SQL文を直接ecordsetで実行しデータ変更
- 8.データの一括処理
- アプリ実例・関連する項目
- サンプルファイル
1.データベースへの接続方法
「DAOでAccess・Excel・CSV等へ接続・操作」でも説明しましたが、ExcelのVBAから「Microsoft Access」「Excelのワークシート」「CSV等のテキストファイル」のデータベースに接続・操作する方式には、主に「ODBC」「DAO」「ADO」の3種があります。今回はADO方式の内、ODBC用のMSDASQLプロバイダーを使ったルート(図01では、黒線のルート)について説明します。
図01
これ以外の接続・操作については、以下を参照下さい。
・DAOでAccess・Excel・CSVに接続・操作
・ADOでAccess・Excel・CSVへ接続・操作(JET・ACEプロバイダー編)
・ADOでAccess・Excel・CSVへ接続・操作(MSDASQLプロバイダー編) ←今回
・ODBCでAccess・Excel・CSVへ接続・操作
なお、今回は「ADOでAccess・Excel・CSVへ接続・操作(JET・ACEプロバイダー編)」と同じADO法であるため、重複する部分が多くあることをご了承下さい。
2.ODBCについて
まず、ODBC(Open Database Connectivity)について説明をします。ODBCとは、Microsoftが作ったデータベースに接続する手順です。データベースには多くの種類がありますが、それぞれに対応したODBCドライバーを使うことで、ユーザー側は同じようなコードで様々なデータベースにアクセスできます。
ODBCの設定をするには、Windowsの「コントロールパネル」から入ります。
図02のように、コントロールパネルの「システムとセキュリティ①」→「Windowsツール②」を選択すると、その中にODBCのアイコン③が現れます。(Windowsのバージョンにより、少し違うかもしれません)
図02
また、コントロールパネルの右上の検索ボックスに「ODBC」と入力④する事で、図03の右図のようにODBC⑤を絞り込む事ができます。
図03
ODBCの設定アイコンには、図02の③・図03の⑤のように、最近では32ビット版と64ビット版の2つがありますが、どちらを使うかは「使用するアプリケーション(今回だとExcel)のビット版」で決まります。つまり、Excel(≒Office)が64ビット版であれば「ODBC(64ビット)」を、32ビット版であれば「ODBC(32ビット)」を選択します。
ODBCの設定アイコンを開くと、図04のように、いくつかのタブが並んでいます。今回は「ユーザーDSN」タブと「ドライバー」タブを使用します。
図04
なお「ユーザーDSN」と「システムDSN」は内容的には同じですが、PC内に複数のユーザーがいる場合「ユーザーDSN」は現在ログインしているユーザーのみが使え、「システムDSN」は全ユーザーが共通して使えるもの という違いがあります。
図04は64ビット版のものですが、32ビット版でもほぼ同じ内容です。
また、64ビット版Excelの入ったPCで32ビット版のODBCを調べると、昔のファイル(例えば、Accessの *.mdb)にしかアクセスできないように見えます。しかし32ビット版Excelの入ったPCで32ビット版ODBCを調べると、ちゃんと最近のファイル(*.mdb と *.accdb)にもアクセスできるドライバーが入っていることがわかります。つまり「Excelのビット版に合わせたドライバーがインストール」されていますので心配ありません。
(必要なドライバーが入っていない場合もあるようなので、確認は必要と思います。)
2-1.ODBCドライバー
使用可能なODBCドライバーは、図04の右側のようにリストになっていますので、その中から選択し、Connectionオブジェクトへ指定します。Connectionオブジェクトに対してどのように指定するかは様々な方法があり、詳細は「データベース接続までのコード例」で説明しますが、「"Driver=Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb);"」のように「ドライバー名を指定した文字列」を作るところまでは共通です。
なお、ドライバー名をコード上に指定する際には、以下のことに注意します。
・文字列は、カッコ内も含めて正しく書き写す ・スペースの位置と数も正しく書き写す ・大文字小文字は同じ文字と認識される ・半角と全角は異なる文字と認識される |
2-2.DSN
DSN(Data Source Name)は、簡単に言えば「ODBCドライバーとデータベースファイル名をセット」にしたものです。ODBCでデータベースに接続する際は、最低でもドライバー名とデータベースファイル名を指定する必要がありますが、この代わりにDSNを指定すれば接続できることになります。図04の左図のように「DSNタブ」を開くと、すぐに使用可能なDSNが並んでいます(但し、データベースファイル名は未設定)。このダイアログでは、図05のようにDSNを新作したり、内容を修正したりすることができます。
図05
DSNリストの右には3個のボタンが並んでいます。
一番上の「追加①」ボタンは、新たなDSNを作成するものです。まず最初にODBCドライバーを指定④(図05の右上)し完了ボタンをクリックすると、次にDSN(データソース名)を入力⑤するダイアログ(図05の右下)になります。
リストからDSNを選択した後「構成③」ボタンを押しても、名前を変更⑤できます。
二番目の「削除②」ボタンは、リスト選択したDSNを削除するものです。
三番目の「構成③」ボタンをクリックすると、以下(図06など)で説明するように、データベースファイル名などを設定することができます。
なおこの構成ダイアログの内容はドライバー毎に異なります。
(DSNの名前) 図05の⑤に設定するDSN(データソース名)ですが、プログラム側から呼び出す際は「大文字小文字は同一」と判断されるようです。 また名前の区切り等に使う「スペース」は、図05の左図のリストでも分かるように「名前の文字列の間」に入れることは大丈夫そうです。しかしスペースを文字列の先頭や末尾に入れてしまうと、構成のダイアログが開かなくなり編集不可となりますので注意が必要です。 (レジストリエディタで削除する事は可能ですが、失敗するとWindowsが起動しなくなる危険性があります。) |
2-2-1.AccessのDSN
Accessのドライバーを選定した時の構成ダイアログは、下図(図06)のようになります。図06
Access構成ダイアログでは、まずデータベースの「選択①」ボタンをクリックし、データベースファイルを設定⑤します。
また「詳細設定③」ボタンをクリックすると、新たなダイアログ⑧が開き、Accessファイルに対するログイン名・パスワード設定や、各設定値の変更が可能です。リスト⑨の各項目を選択すると、下部⑩に項目名と値のボックスが出ますので編集できるようになっています。
右下部の「オプション④」ボタンではダイアログが下に伸び、ページタイムアウトやバッファサイズ等の変更ができます。
なお、「作成②」ボタンから、新しいAccessデータベースファイルを作成⑥することも可能です。その際は、バージョンを指定⑦する必要があり、「バージョン4.xでは、*.mdbファイル」が作成され、「バージョン12.xでは、*.accdb」ファイルが作られます。
mdbファイルにはJetエンジンで作られるものと、ACEエンジンで作られるものの2種がありますが、試してみたところ「Jetエンジンで作られるmdbファイル」のようです。
また、ワークグループ情報(データベースへアクセスするためのIDやPWなど)をファイル化したシステムデータベース(System.mdw)がある場合は、システムデータベースの「データベース⑬」のラジオボタンをクリックし「システムデータベース⑫」ボタンをクリックすることで、新たなダイアログ⑬が表示されファイル選択ができます。
2-2-2.ExcelのDSN
ExcelのDSNについて下図(図07)で説明します。図07
Excelの構成ダイアログでは、まずデータベースのバージョン①をドロップボックス④から選択します。既定はExcel 12.0(Excel2007~)のようです。
それ以前のバージョンも選択できますが、「Excel 3.0、及び Excel 4.0」では、ブックの選択ボタンが「フォルダーの選択」ボタンへと名称が変わり、フォルダーしか選択できなくなります。ちょうど現在のCSVファイルのような立場だったのかもしれません。またExcel2003が抜けていますが、「Excel 97-2000」「Excel 12.0」のどちらでも大丈夫そうです。
バージョンの選択が完了したら「ブックの選択②」ボタンをクリックし、ダイアログ内⑤を操作してExcelブックを選択します。
もしかしたらバージョン選択④の目的は、このダイアログ⑤に於ける表示拡張子を決める役目なのかもしれません。
右下の「オプション③」ボタンをクリックすると、ダイアログが下に伸び⑥、「スキャンする行数」の入力と「読み取り専用」有無の選択が可能です。
この「読み取り専用」にレ点を入れると、Insert文などの実行時にエラーが発生します。但し、読み取り専用に設定したDSNを指定するのと同時にコード側で「ReadOnly=0(=False)」 の指定をすると、Insert等も可能になります。逆はダメなので、コード側の指定が優先されるようです。
「スキャンする行数」は、データ列のデータ型を判定するためのスキャン行数(MaxScanRows)です。既定値は「8」ですが、値を変更しても処理内容は変わりません(他の複数サイトでも解説されていますが、このMaxScanRows設定はバグにより無効となっているようです)。
また「ゼロを設定すると全行をスキャン」との説明も見受けられますが、ここではゼロを入力する事はできません。
2-2-3.テキスト(CSV)のDSN
CSV(テキストファイル)を選定した時の構成ダイアログは、下図(図08)のようになります。図08
テキストファイルの場合は、データベース相当は「テキストファイルがあるフォルダー」となります。ですので、テキストの構成ダイアログでは「現在のフォルダーを使用する①」というチェックボックスをまず確認します。
チェックボックスにレ点がついていると、ODBCが置いてある「C:¥windows¥system32」辺りになってしまいますので、通常はレ点を外し「フォルダーの選択②」ボタンをクリックすることでダイアログ④が表示され、フォルダーを選択します。
右下の「オプション③」ボタンをクリックするとダイアログが下に伸び、テキストファイルの拡張子の追加/削除ができるようになります。
テキストファイルのあるフォルダーを指定④し、ファイルの拡張子を指定⑤した後で「書式の定義⑥」ボタンをクリックすると、テキスト形式の定義ダイアログ⑦が現れます。そのダイアログの左上リストボックス(「テーブル」と表示されている)には「指定したフォルダー内に存在する、指定した拡張子のファイル」が一覧表示されます。テキストデータベースにしてみれば、これが「テーブル」相当になります。
リスト上のファイル(テーブル相当)を選択し、右側の「推量⑨」ボタンをクリックすると、右のリストボックスに「列の一覧」が表示されます。先頭行が列名である場合には「列名の見出し⑧」にレ点を付けておけば、ちゃんとした列名となります(列名の見出し⑧にレ点が付いていないと、F1・F2 ・・・等と表示されます)。
列のリストを選択すると、右リスト下にデータ型・名前・幅が表示されます。データ型は、左側の「スキャンする行数⑩」の行数だけ読み込んで、数の多いデータ型を表示しているようです。ちょっと便利そうな機能です。
(テキストの列情報の編集) 図08のダイアログ⑦の右下の「列情報」の右端には、列を追加・変更・削除できるボタンも並んでいます。実際に追加ボタン等を使ってみると変更されているように見えますが、実際のファイル内で列が追加できたり、削除されたりは無さそうです。しかしその情報は、指定したフォルダー内の「schema.ini」内に保存されている(存在しなければ新規作成される)ようで、再度呼び出すと変更内容は記憶されています。 但し、データ型などを一旦変更をしてしまうと、その保存された情報による悪影響が発生し、データを操作しようとすると「抽出条件でデータ型が一致しません」などのエラーが発生する事があります。もしそうなってしまった場合は「schema.ini」を削除するのが良いと思います(編集も出来そうですが、今回は省略します)。 |
3.ADOのオブジェクトについて
ADOでのデータベースへの接続・操作には、ADOの「Connection」「Command」「Recordset」の各オブジェクトを図09のように組み合わせて行います。表内の指定内容の「テーブル」と「SQL文」は、Recordset.OpenメソッドやCommand図09
まず「各オブジェクト、及びそのメソッド・プロパティ」について説明をした後、図09で示した各ルートの実際のコードを紹介します。とりあえず接続するコードを知りたい場合は、先に「データベースに接続・操作するためのコード例」を確認下さい。
3ー1.ADOオブジェクトの種類
ADO直下には図09で示した以外にも、多くのオブジェクトが存在します。図10はそのオブジェクトが、バージョンにより使えるか否かと、実行時バインディング時にCreateObjectで生成可能か否かをまとめたものです。オブジェクト | 内容 | 事前バインディング | 実行時 | |
---|---|---|---|---|
Ver 2.8 | Ver 6.1 | Create | ||
Command | データソースに対して実行する特定コマンドの定義 | 〇 | 〇 | 〇 |
Connection | データソースへの接続 | 〇 | 〇 | 〇 |
Error | 発生するアクセスエラーの詳細情報 | 〇 | 〇 | 〇 |
Errors | 〇 | 〇 | × | |
Field | データ列 | 〇 | × | × |
Fields | 〇 | × | × | |
Parameter | Commandオブジェクトに関連付けられた引数 | 〇 | 〇 | 〇 |
Parameters | 〇 | 〇 | × | |
Property | ADOの動的特性 | 〇 | 〇 | × |
Properties | 〇 | 〇 | × | |
Record | Recordsetの行、又はファイルシステム内のディレクトリやファイル | 〇 | 〇 | 〇 |
Recordset | コマンド実行により返された結果 | 〇 | 〇 | 〇 |
Stream | データの流れ | 〇 | 〇 | 〇 |
これらのオブジェクトの内、データベースとの接続・操作にかかわる「Connection」「Recordset」「Command」オブジェクトについて、今回説明していきます。
なお後述する参照設定(図11)で「バージョン6.1」を選択した場合、図10の「Ver6.1」列で分かるように、Field(Fields)オブジェクトは存在しません。ですので「RecordsetのFieldsをADOのFieldsオブジェクトで受け取る(今回は、その手法については説明を省略しています)」場合は、バージョンを2.8とする必要があります。
但し実行時バインディング(CreateObject使用)の場合は、Fieldsオブジェクトは単なるObject(総称オブジェクト型)として宣言しますので、RecordsetのFieldsを「一般のObject型」として受け取る事が可能です。
3ー2.ADOオブジェクト生成
ADOでデータベースとやり取りするには、まずADOオブジェクトを生成する必要があります。その生成方法には以下の2種類があります。・「事前バインディング」・・・コードを実行する前に生成
・「実行時バインディング」・・コードを実行した時に初めて生成
事前バインディングの特徴は、コード作成時にインテリセンス(コード補完機能=使用可能なプロパティ等が表示され、選択することが可)が使えることと併せ、効率が良い(≒実行速度が速い)ことです。
一方実行時バインディングは、実行しているPCに合わせたライブラリを呼び出すため、PC環境の異なる複数ユーザーにマクロを配布する時でも安全度は高いです。
3ー2ー1.事前バインディング
事前バインディングでは、VBE(コードを書くウィンドウ)上部の「ツール」→「参照設定」から、図11のように「Microsoft ActiveX Data Objects X.X Library」にチェックをし有効にします。図11
X.Xの部分はバージョンを表していますが、最新Excelでは「2.8」①までと、少し飛んで「6.1」②が選択できるかと思います。
通常は「最新のもの」を選択するのが良いとされています。しかし複数のPCを対象に動かすようなシステムの場合に「最新バージョン」を選択して作ってしまうと、もしその「最新バージョン」がインストールされていないPCが存在する場合は、うまく動かない可能性が出てきます。ライブラリを選択する際には「どのPCにも入っているバージョン」を選ぶのが良いと思います。
なお、バージョンの2.8と6.1では、図10のようにADO直下のオブジェクトが異なります。最新の6.1にはField(Fields)オブジェクトがありません。但し、図57の234行目のような「カーソル行の対象列」を示すFieldsプロパティは大丈夫です。このFieldsはRecordsetオブジェクトのFieldsだからです。
プログラム的には、図11のようにADOのライブラリーを参照設定した上で、図12のように「オブジェクト変数をADOオブジェクトとして宣言」→「New句を使って生成」した後、オブジェクト変数を処理に使用します。
- '========== ⇩(1) 事前バインディングでの宣言と生成 ============
- Dim cn As ADODB.Connection '←Connectionオブジェクトの宣言
- Dim rs As ADODB.Recordset '←Recordsetオブジェクトの宣言
- Dim cmd As ADODB.Command '←Commandオブジェクトの宣言
- Set cn = New ADODB.Connection '←Connectionオブジェクトの生成
- Set rs = New ADODB.Recordset '←Recordsetオブジェクトの生成
- Set cmd = New ADODB.Command '←Commandオブジェクトの生成
- ( 生成したcn,rs,cmdオブジェクト変数を使い、接続やデータ取得・変更の処理・・・等)
01~03行目では、各オブジェクト型毎に変数宣言をします。
05~07行目では、New句を使ってオブジェクトを生成します。
オブジェクト生成後は、そのオブジェクト変数(図12では、cn,rs,cmd )を使って処理作業を行います。
3ー2ー2.実行時バインディング
実行時バインディングの場合は、使用するオブジェクト毎にCreateObjectを使って生成します。なおCreateObjectで生成できるADOオブジェクトは、図10で示したように一部分のみになります。
- '========== ⇩(2) 実行時バインディングでの宣言と生成 ============
- Dim cn As Object '←Connectionオブジェクトの宣言
- Dim rs As Object '←Recordsetオブジェクトの宣言
- Dim cmd As Object '←Commandオブジェクトの宣言
- Set cn = CreateObject("ADODB.Connection") '←Connectionオブジェクトの生成
- Set rs = CreateObject("ADODB.Recordset") '←Recordsetオブジェクトの生成
- Set cmd = CreateObject("ADODB.Command") '←Commandオブジェクトの生成
- ( 生成したcn,rs,cmdオブジェクト変数を使い、接続やデータ取得・変更の処理・・・等)
21~23行目では、単なるObject型として変数宣言をします。
25~27行目では、CreateObject関数を使って各オブジェクトを生成します。オブジェクト生成後は、そのオブジェクト変数(図13では、cn,rs,cmd )を使って処理作業を行います。
4.Connectionオブジェクト
Connectionオブジェクトには複数のプロパティ・メソッドが存在します。データベースに接続するためには、接続条件を指定したOpenメソッドの実行が必須ですが、Openの前にConnectionStringプロパティ、Providerプロパティなどに接続条件を事前設定させる手法も使えます。
またConnectionオブジェクトのExecuteメソッドを使えば、コマンドが実行できます。
4ー1.Openメソッド他(データベース接続関係)
データベースに接続するには、下記のようにConnectionオブジェクトのOpenメソッドを使います。Connection.Open (ConnectionString, UserID, Password, Option)
ConnectionのOpenメソッドには、4つのパラメータ設定が可能です。全て省略可です(図14)。
パラメータ | 内容 | |
---|---|---|
ConnectionString | 省略可 | 接続情報(図15) |
UserID | 省略可 | 接続時のユーザー名 |
Password | 省略可 | 接続時のパスワード |
Options | 省略可 | 接続の同期/非同期(図26) |
なお、第4パラメータのOptionsは、ExecuteメソッドのOptionsとは全く別なので混同に注意です。
4ー1ー1.第1パラメータ(ConnectionString:接続情報)
図14の第1パラメータ(ConnectionString)には、図15のような情報を「文字列」として組み込みます。各項目の区切りは「;(セミコロン)」です(最後の項目の末尾には、セミコロンは必須ではありません)。図15では「ODBC列」と「JET・ACE列」の2通りを併記していますが、「ODBC列」の情報を使うことで、今回の図01のように「MSDASQLプロバイダー」→「各ODBCドライバー」→「各データベース」という流れで接続・操作ができます。
なお「ODBC列とJET・ACE列の混在」はできません。
内容 | ODBC | JET・ACE |
---|---|---|
プロバイダー | Provider= | Provider= |
ドライバー | Driver= | ー |
データベース名 | DBQ=データベース名 | Data Source=データベース名 |
DSN名 | DSN=DSN名 | ー |
ユーザー名 | UID=ユーザー名 | User ID=ユーザー名 |
パスワード | PWD=パスワード | Password= |
URL名 | (URL=URL名) | ー |
読取/書込 | ReadOnly= | ー |
拡張プロパティ | ー | Extended |
ODBC接続に必須な第1パラメータの内容は「プロバイダー」と「ドライバー名」「データベース(DB)名」です。しかし、ドライバーとデータベースの代わりに「DSN」を指定する方法もあります。まとめると、図16のように3通りが考えられます。
図16
まず、プロバイダーの指定は必須ですが、既定値が「MSDASQL」ですので省略も可能です。
1つ目の方法(図16の①)は、「ODBCドライバー」と「データベース」を指定する方法です。ODBCドライバーには、図04の右側で示したドライバーリストから種類に合った1つを指定します。データベースには、AccessやExcelのファイル名を、CSVファイルの場合はフォルダー名を指定します。
2つ目の方法(②)は、「DSN」で説明したDSN(Data Source Name)を指定する方法です。DSNを作成するにはドライバーの指定が不可欠ですので、それに加えてデータベースを事前に設定しておけば、ドライバーとデータベースの両方が指定されている事になり、DSNの指定のみでOKとなります。
3つ目の方法(③)は、データベースが未設定のDSNの指定と合わせて、データベース設定を別個に指定する方法です。この手法でも、ドライバーとデータベースの両方が指定されていることになるのでOKです。
なお、データベース設定済みのDSNに対してこの方法を使うと、DBQ=で設定するデータベースの方が優先されます。
4ー1ー1ー1.プロバイダー名
ODBCを使用する際は、プロバイダー名には「MSDASQL」を使用します。なお、ADOではプロバイダーの既定値は「MSDASQL」ですので、省略も可能です。このプロバイダーは標準でWindowsにインストールされていますが、それを確認するには「WindowsのPowerShell」で下記コマンドを実行します。
「 (New-Object data.oledb.oledbenumerator).getElements() | select SOURCES_NAME, SOURCES_DESCRIPTION 」
結果は、例えば図17のようになり、MSDASQLプロバイダー(赤矢印)が入っている事が確認できます。
図17
なおPowerShellには何種類かがありますが、ビット版で考えると「PowerShell」と「PowerShell(x86)」の2種類です。最近のWindows(64ビット)で考えると、単なる「PowerShell」が64ビット版で、「PowerShell(x86)」が32ビット版です。
インストールされている(=使用可能)なプロバイダーを調べるには、以下のようにします。
・Windowsが64ビット版 + Officeが64ビット版 → 「PowerShell」で上記コマンドを実行
・Windowsが64ビット版 + Officeが32ビット版 → 「PowerShell(x86)」で上記コマンドを実行
・Windowsが32ビット版 + Officeが32ビット版 → 「PowerShell」で上記コマンドを実行
Windowsが32ビット版の場合、そのPowerShellは32ビット版となります。また、Officeは32ビット版に限りられます。
つまり「Officeのビット版と同じビット版のPowerShellを使用」すると、使用可能なプロバイダーが分かるようです。
図17は「Windowsが64ビット版 + Officeが64ビット版」の時のもので、PowerShellも64ビット版ですが、32ビット版のPowerShell(x86)でコマンドを実行してみても、以下のようにMSDASQLが入っている事が分かります。
図18
プロバイダー名をConnectionStringに指定する場合は、"Provider=MSDASQL;" とします。
また、Providerプロパティに直接指定する場合は、Connection.Provider="MSDASQL"とします。
4ー1ー1ー2.ドライバー名
ドライバーは、対象となるデータベース種に対応したものを選択します。且つ、そのドライバーを使うアプリ(今回だとExcel)のビット数に合ったものにする必要があります。64ビット版のWindowsには、64ビット版ODBCと32ビット版ODBCがありますが、例えば私の64ビット版Officeが入っているPCでは、図19のように、ドライバー種はかなり違います。
図19
一方、32ビット版Officeが入っているPCでは図20のようになります。
図20
図19と図20を比較してみると、Officeのビット版と同じビット版のドライバー側に「必要とするドライバー」が入っていることが分かります。Officeがインストールされる際に、それに関連するドライバーもインストールされている様です。
且つ「ドライバーの名称は、32ビット版も64ビット版も同じ」ようなので、ビット版が混在する複数のPCに対してのプログラムでも、ビット版を意識せずに同じコードで動くと言えます。
なお、ExcelとAccessについては、ドライバーは下記の1種類ずつなので、一意に決まりそうです。
・Excel :Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)
・Access:Microsoft Access Driver (*.mdb, *.accdb)
一方CSVファイル用のドライバーは、色々な種類がありそうですが、CSVと言えども「Officeのビット版と同じビット版のODBCに入っているドライバー」のみが対応できます。つまりCSV(テキストファイル)には、以下のドライバーを使うのが安全です。
・CSV :Microsoft Access Text Driver (*.txt, *.csv)
なお、32ビット版のOfficeであるならば「Driver da Microsoft para arquivos texto (*.txt; *.csv)」等でも動きます。但しスペルに気を付ける事と、カンマの代わりに「;(セミコロン)」を使っている事にご注意下さい。
このドライバー名をConnectionString等に指定する場合は、ドライバー名を波かっこ( { } )で括り、「Driver=」の後ろに続けます。
"Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" など
4ー1ー1ー3.データベース名
データベース名は、対象とするデータベースの種類により図21のように変わります。データベース名 | |
---|---|
Access | ファイル名(*.accdb, *.mdb) |
Excel | ファイル名(*.xlsx 等) |
CSV等 | CSVファイルがあるフォルダー名 |
AccessやExcelのように、ファイル内に複数のテーブルを持てるタイプでは「ファイル名」がデータベース名となりますが、CSVファイルのようにファイル=テーブルのようなものは「フォルダー名」がデータベース名となります。
データベースを指定するには「DBQ=」を使用し、例えば以下のようにします。
・Access:"DBQ=C:¥Data¥its-041.accdb;"
・Excel :"DBQ=C:¥Data¥its-041.xlsm;"
・CSV :"DBQ=C:¥Data¥;"
なお、CSVの文字列最後の¥印は、あっても無くても変わりません。
(テーブル名) 各データベースに於ける「テーブル」について図22に示します。
Accessに於けるテーブルは、通常のデータベースとしてのテーブルと同じ扱いになります。 Excelでは、ワークシートがテーブル扱いとなります。例えばSheet1にデータがあるとし、Recordset.Openの第1パラメータにテーブル名を指定するような場合は、「"Sheet1$"」のように「シート名+$マーク」とします。またSQL文の中で使用する場合は、更に角カッコで囲み「Select * from [Sheet1$] 」のようにします。 CSVでは、CSVファイルそのものがテーブル扱いとなります。ファイル名がits-041.csvとすれば、テーブル名指定の場合はファイル名をそのまま使用して「"its-041.csv"」とし、SQL文の中で使う場合は角カッコで囲み「Select * from [its-041.csv] 」とします。 |
なおAccess,Excel,CSVはでは、上記のように「DBQ=」を使用してデータベースを指定しますが、SQL Serverでは「DATABASE=」を使用するようです。
4ー1ー1ー4.DSN名
ドライバーとデータベースの情報を1つにまとめた「DSN」名をODBCダイアログから選んで指定します。図23は左右図とも私のPCのものですが、64ビット版OfficeがインストールされたPCですので、同じ64ビット版のODBC(左側)からDSNを選ぶことになります。
図23
ODBCを初めて使用する状態では、図23のように「Excel File」と「MS Access Database」は既定で作られています(違う場合もあるとは思います)ので、データベースファイルを設定すれば、すぐ使えることになります。しかしCSV等のテキストファイルについては「テキストのDSN」などを参考に元から作る必要があります。
一方、32ビット版Officeが入っているPCでは図24のようになります。
図24
図23と図24を比較してみると、64ビット版も32ビット版も、同じ名前でExcelとAccessのDSN(データベースは未設定)は作られている事が分かります。ですので図16の③のパターンであれば、面倒なドライバー名を書き写さなくても、複数人に配布するプログラムに盛り込めるとも言えます。
しかし、このDSNはユーザー自身が簡単に名前変更などが可能ですので、「DSNの変更禁止」を徹底しておく必要があります。
また同様に、データベースを設定したDSNを使う場合も、1台1台のPCへのDSN設定が必要になりますし、例えそれが可能だったとしても、ユーザー自身によるDSN変更の懸念は無くなりません。
まとめると、DSNを使うとプログラムが単純になりますし、オプション設定等もありますので、個人で使うにはメリットが大きいと思います。しかし複数人で同じプログラムを使う場合は、図16の①の「ドライバー設定 + データベース設定」の方が安全だと考えます。
ConnectionオブジェクトへのDSNの設定時は、ConnectionStringに"DSN=Excel Files;" 等と指定します。
4ー1ー1ー5.ユーザー名、パスワード
データベースに「ユーザー名」や「パスワード」が設定されている場合は、ConnectionStringに指定します。なお、Excelの「ブックの保護」で設定したパスワードは対象外です(「Password=ブック保護のパスワード」を指定しても、データは取得できません)。
このユーザー名・パスワードを「ExcelのVBA側で作成したAccessファイル」に設定しようと試みました。やり方としては、ADOXのUsersコレクションから、NameプロパティとChangePasswordメソッドを使うと思われますが、残念ながらExcel VBAからは操作できませんでした。
実際のAccessで作成されたデータベース(*.accdb, *.mdb)の場合は当然設定が可能だと思います。
またこの内容は、Openメソッドの第2・第3パラメータと同じと思われます。
4ー1ー1ー6.URL名
URL名は、例えば「https://www.〇〇/sample.xlsx」のようなものはプロトコル上から無理だとは思いましたが、LANの共有サーバーのような「¥¥Server1¥Excel¥sample.xlsx」であれば大丈夫かな?と考えて試してみましたが、ダメでした。共有サーバーの場合はDBQを使い「DBQ = ¥¥Server1¥Excel¥sample.xlsx」等とすれば動くようです。それならば「URLはどういう場面で使うのか」については、結局わかりませんでした。ですので図15ではカッコ付きとしてあります。
4ー1ー1ー7.読取/書込
読取/書込の「ReadOnly=」については、私もずっと勘違いしていましたが、「"ReadOnly=True"」や「"ReadOnly=" & True (文字列としては "ReadOnly= -1" になる)」では、読み取り専用の状態にはならない事がわかりました。読み取り専用にするには「"ReadOnly=1"」とすることが必要です。
それ以外は全て「"ReadOnly=0"(書き込みもOK)」となり、注意しなければいけないのはスペースで「"ReadOnly =1"」のように「イコール記号の前にスペースを入れる」と「ReadOnly=0(書き込みOK)」となってしまいます。ちなみに「"ReadOnly=False"」と指定すると、"False"は文字列なのでゼロ値とみなされるため、ReadOnly=0 と解釈されるようです。
またReadOnlyを省略したときの既定値ですが、以下のようにドライバー毎に異なります。
ドライバー | ReadOnly= 省略時 |
---|---|
Access | False(書込可) |
Excel | True(読込のみ) |
Text(CSV) | False(書込可) |
Excelだけは「省略するとReadOnly=1(True)」なので、書き込みが必要な場合は「ReadOnly=0;」の記述が必要です。
またAccessとCSVは、省略すると書き込み可となります。ですので書き込みさせたくない場合は「ReadOnly=1;」とすれば良いのですが、基本的には「常にReadOnly=〇〇; を記述」し、データベースへの処理を明確にするのが大切と思います。
(Modeプロパティ) ADOでは、ConnectionオブジェクトのModeプロパティを操作する接続文字列として「Mode=Read;」や「Mode=RadWrite;」も存在するようです。しかしExcelのVBAでは「Mode=Read;」は使えそうですが、「Mode=RadWrite;」ではエラーが出てしまいます。 やはりExcelでは「ReadOnly=0/1」を使うしかなさそうです。 |
(HDRなどの設定) HDR(データの先頭行がタイトルか否か)、IMEX(読取/書込)、FMT(データ区切り記号)の設定等は、ACE・Jetプロバイダーでは「拡張プロパティ(Connection.Properties("Extended Properties")= )」から可能でした。しかしMSDASQLプロバイダーでは、同じように指定しても機能してくれず、その設定方法が分かりません。 但し、DSNの中では図08の⑧「列名の見出し」をOFFにすれば、1行目もデータとして読み込んでくれるようです。しかしExcelのDSN(図07)にはそれらしいチェックボックスが見当たらず、「MSDASQLでは、HDRなどの細かい設定は不可能」と考えた方が良さそうです。 |
4ー1ー2.第2・第3パラメータ(UserID、Password)
Connection.Openの第2、第3パラメータは「UserID」と「Password」です。データベース接続にユーザー名とパスワードが必要な場合は設定をします。なおこの項目は、ConnectionStringのユーザー名(UID)・パスワード(PWD)と同じもののようです。4ー1ー3.第4パラメータ(Options:同期/非同期)
Connection.Openの第4パラメータ(Options)には、以下の値を指定します。定数 | 値 | 内容 |
---|---|---|
adAsyncConnect | 16 | 接続を非同期で開く |
adConnectUnspecified | -1 | 接続を同期で開く(既定) |
同期で開く(既定)場合は、Openの処理をしている間は他の処理が出来ませんが、非同期の場合はOpen処理をしている間も次の処理に移る事が可能になります。
例えばOpen処理に多くの時間が必要で、且つ併行して行う作業が存在するようなシステムでは非同期での実行も考えられますが、その場合はOpen処理が「完了したか否か」をStateプロパティ等で確認してからレコードセット取得処理やExecute処理に移る必要があります。
それ以外では、既定の「同期で開く」で良いと思われます。
なお同期・非同期の情報保持は、OpenしたConnectionオブジェクトのどのプロパティが担当しているかは分かりませんでした。ですのでOpen前に「同期・非同期をプロパティ設定」する手法は不明です。
4ー1ー4.データベース接続までのコード例
接続情報を指定してデータベースに接続する手順を、簡単な例で紹介します。まず、Connection.Openメソッドの第1パラメータ(ConnectionString)に「プロバイダー名+ドライバー名+データベース名を指定」する書き方を図27に示します。なおADOオブジェクトは実行時バインディング(以下同様)としています。
- '========== ⇩(3) Openメソッド実行時に全て指定 ============
- Dim cn As Object '←実行時バインディングのConnectionオブジェクト
- Dim s As String '←ConnectionStringの内容
- Set cn = CreateObject("ADODB.Connection") '←Connectionオブジェクトを生成
- s = "Provider=MSDASQL;" '←プロバイダー
- s = s & "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←データソース情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←データソース情報
- cn.Open s '←プロバイダー+ドライバ+データソースをOpenメソッドの第1パラメータに指定
- (処理)
44行目「Set cn = CreateObject("ADODB.Connection")」で、Connectionオブジェクトを生成します。
46~48行目で、Openメソッドの第1パラメータ(ConnectionString)の文字列を作成しています。プロバイダー(Provider=)としては今回「MSDASQL」を、ドライバー(Driver=)としては図19・図20のドライバー名「Microsoft Access Driver (*.mdb, *.accdb)」を波かっこ( { } )で括ります。またデータベース(DBQ=)として「ThisWorkbook.Path & "¥" & "its-041.accdb"」を指定します。なお、各項目はセミコロン( ; )で区切ります。
パラメータ用の文字列が完成したら、50行目「cn.Open s」で、Openメソッドの第1パラメータに接続情報を渡して、データベースに接続します。
図27では、全ての接続文字列をOpenメソッドのパラメータに指定して、データベースに接続させています。しかし、Connectionオブジェクト配下には様々なプロパティ(図28:接続情報に関するもののみ)があり、そのプロパティに値を直接指定したり、Openメソッドへのパラメータと併行して指定する方法もあります。
プロパティ | 内容 | |
---|---|---|
ConnectionString | 接続情報文字列 | |
Provider | 接続するプロバイダ名 (既定:MSDASQL) | |
Properties コレクション | Password | パスワード |
User ID | ユーザー名 | |
Extended Properties | 接続情報文字列 |
なおPropertiesコレクションには「Data Source」プロパティもあるのですが、MSDASQLでのDBQ=の値は「Data Sourceプロパティに格納しても認識されない」のでエラー発生します。この点は、プロバイダーにACEやJetを使った時との大きな違いかもしれません。
この各プロパティに接続情報を格納する前に、まず図15の接続情報を分類しておく必要があるようです。私が整理したのは図29のように3種に分ける方法です。
種類 | 内容 | 接続情報 |
---|---|---|
A | プロバイダ情報 | Provider= |
B | 必須情報 | Driver=、DBQ=、DSN= |
C | 準必須情報 | ReadOnly=など(UID=、PWD=はここか?) |
接続情報の内、UIDとPWDがどの分類に入るかは特定できていません。理由は、Excel VBAからデータベース(Access)ファイルに対し、ユーザー名(UID)とパスワード(PWD)が設定できなかったためです。パスワード等を設定していないAccessファイルに対して、UIDとPWDを接続情報として指定しても、どうやら無視されているようで、どこに分類されるのかが判断できませんでした。
またBは「Driver+DBQ」「DSN」「DSN+DBQ」と、図16のように3種ありますが、この組み合わせとしてBに分類されるようです。
これらの接続情報を指定する場所としては、以下の4箇所が考えられます。
・Connection.Provider= 接続情報
・Connection.ConnectionString = 接続情報
・Connection.Properties("Extended Properties")= 接続情報
・Connection.Open (接続情報)
もちろん、どこに指定しても良いわけでは無く、できる箇所・できない箇所がありますし、「ConnectionString と Properties("Extended Properties")を併行して使用してしまうと、後から設定した方のみが有効」となるため、どちらか一方のみの使用が良さそうです。
試してみると指定可能な場所は以下のようになり、これ以外の組み合わせではエラーとなりました。なお表内のA・B・Cは図29のA・B・Cです。
指定箇所 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|---|
Connection | A | A | A | ||||||
Connection Connection | A | B+C | C | A | C | A+C | |||
Connection | A | B+C | B | B+C | A+B | B |
なお、MSDASQLプロバイダーをProviderに指定する際は、単純に「Connection.Provider = "MSDASQL"」としますが、それ以外の設定場所の場合は「"Provider = MSDASQL;"」という文字列にします。
例えば図30のNo5をコードで表現すれば以下(図31)のようになります。
- '========== ⇩(4) 接続情報を分割して指定1 ============
- Dim cn As Object '←実行時バインディングのConnectionオブジェクト
- Dim s As String '←ConnectionStringの内容
- Set cn = CreateObject("ADODB.Connection") '←Connectionオブジェクトを生成
- s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←ドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←データソース情報
- cn.Provider = "MSDASQL;" '←プロバイダー(A)
- cn.ConnectionString = "ReadOnly=1;" '←読取/書込情報をConnectionStringプロパティに渡す(C)
- cn.Open s '←ドライバ情報+データソース情報をOpenメソッドに渡して実行(B)
- (処理)
66~67行目で、ドライバー情報とデータソース情報の文字列をまとめます。
69行目「cn.Provider = "MSDASQL;"」でプロバイダーを指定します。なおMSDASQLは既定値なので、69行目が無くても問題ありません。
70行目「cn.ConnectionString = "ReadOnly=1;"」で、読取/書込の情報をConnectionStringプロパティに指定します。
72行目「cn.Open s」で、ドライバー情報とデータソース情報をパラメータに指定してOpenメソッドを実行します。
このコードであれば、データベースに接続できます。
しかし、BとCを逆にしたコード(図32)では、エラーが出てしまいます(このパターンは、図30には入れていません)。
- '========== ⇩(5) 接続情報を分割して指定2(ダメな例) ============
- Dim cn As Object '←実行時バインディングのConnectionオブジェクト
- Dim s As String '←ConnectionStringの内容
- Set cn = CreateObject("ADODB.Connection") '←Connectionオブジェクトを生成
- s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←ドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←データソース情報
- cn.Provider = "MSDASQL;" '←プロバイダー(A)
- cn.ConnectionString = s '←ドライバ情報+データソース情報をConnectionStringプロパティに渡す(B)
- cn.Open "ReadOnly=1;" '←読取/書込情報をOpenメソッドに渡して実行(C)
- エラー発生し処理不可
89行目までは図31と同じですが、90行目「cn.ConnectionString = s」でドライバ情報とデータソース情報をConnectionStringプロパティに渡し、92行目「cn.Open "ReadOnly=1;"」で、←読取/書込情報をOpenメソッドに渡して実行しています。
これだとエラーが発生し、データベースには接続できません。
この結果からルールを見つけるために図30を良く見てみると、まず「Connection.Provider=」に指定できるのは、当然ながらProvider情報(図29のA)のみです。
その他の情報(図29のBとC)はConnectionStringに指定する方法とOpenメソッドのパラメータに設定する方法が考えられますが、「Openメソッドのパラメータにする場合、Bは必須」となっています。
接続情報の指定の仕方として他のサイトでは、図30の1~3あたりを紹介することが多いように思いますが、違う組み合わせでも接続できるため、状況に合わせて指定して下さい。
またConnectionStringプロパティに文字列を指定する際、「Cn.ConnectionString = "Extended Properties=""接続文字列"""」のように「Extended Properties=」の後ろ側に指定する手法を紹介しているサイトもあります。しかし、図31の70行目のように「Cn.ConnectionString = "接続文字列"」と、直接ConnectionStringプロパティに指定する場合と差は無さそうです。
プロパティ値の動きを確認してみると、動作としては「Extended Properties=」があっても無くても、一旦ConnectionStringプロパティに値が設定され、その値が適切な場所(ConnectionオブジェクトのPropertiesコレクションのExtended Propertiesプロパティ 等)に格納されます。
一般的に良く紹介されている例として、図30のNo.3に相当するコードを下記(図33)で紹介します。
- '========== ⇩(6) 各プロパティに値を直接指定 ============
- Dim cn As Object '←実行時バインディングのConnectionオブジェクト
- Dim s As String '←ConnectionStringの内容
- Set cn = CreateObject("ADODB.Connection") '←Connectionオブジェクトを生成
- s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←ドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←データソース情報
- s = s & "ReadOnly=1;" '←その他の情報
- cn.Provider = "MSDASQL" '←プロバイダーを設定(A)
- cn.ConnectionString = s '←ドライバ情報+データソース情報+その他の情報をConnectionStringプロパティに渡す(B+C)
- cn.Open '←パラメータ無しでOpenメソッドを実行
- (処理)
110行目「cn.Provider ="MSDASQL"」で、ConnectionオブジェクトのProviderプロパティに、MSDASQLプロバイダーを設定しています。
111行目「cn.ConnectionString = s」で、ConnectionオブジェクトのConnectionStringプロパティに、ドライバ+ファイル名+その他の接続情報を設定しています。
113行目「cn.Open」で、Openメソッドのパラメータは無しでデータベースに接続します。
4ー2.Executeメソッド(コマンドの実行)
ConnectionオブジェクトのExecuteメソッドの構文は以下のようになります。戻り値は「Recordsetオブジェクト」です。Set Recordsetオブジェクト = Connection.Execute( CommandText, RecordsAffected, Options )
Recordsetオブジェクトとして受け取る場面は、第1パラメータのCommandTextに「テーブル名」や「SQL文のSelect文」を指定し、戻ったレコードセットに対して処理を行う時だと思いますが、この時の戻り値(Recordsetオブジェクト)のデータは、「読み取り専用」です。その為、取得したデータの出力等の操作のみが可能で、追加・変更・削除処理は出来ない事になります。
なお第1パラメータに「InsertやUpdate・DeleteのSQL文を指定」した場合は、戻り値を操作する訳では無いので、追加・変更・削除処理は可能です(Excelは削除不可、CSVは変更・削除不可 である事は変わりません)。
このようなInsert文等を指定した時は、変更を目的としたレコードセットを受け取る必要が無いので、以下のように戻り値を受け取らず、そのまま実行します。
Connection.Execute( CommandText, RecordsAffected, Options )
なおレコードセットを受け取る必要が無くても、ExecuteメソッドはRecordsetオブジェクトを戻してきます。もし、その戻されたRecordsetオブジェクトがデータか否かを調べる必要がある場合には「戻されたRecordsetオブジェクトのStateプロパティ」を確認します。
値が1(adStateOpen)であればデータとしてのレコードセットであり、ゼロ(adStateClosed)であればデータでは無い(例:Insert文を実行した等)事が分かるようです。なお「Recordset.Close メソッド」を実行すると、State値はゼロ(adStateClosed)になります。
Executeメソッドに指定できるパラメータは、以下の内容になります。
パラメータ | 内容 | |
---|---|---|
CommandText | 必須 | テーブル名、SQL文 等 |
RecordsAffected | 省略可 | Long型の変数に、変更レコード数を戻す |
Options | 省略可 | CommandTextの種類 |
第1パラメータ(CommandText)は必須で、テーブル名、またはSQL文 等を文字列で指定します。
第2パラメータ(RecordsAffected)には、Long型の変数を指定します。第1パラメータにデータ変更を伴うSQL文(Insert・Update・Delete)を指定しExecuteメソッドを実行すると、変更対象となったレコード数がこの変数に戻されます。コードで示すと、図35のようになります。
- '========== ⇩(7) Connection.Executeで変更対象行数を取得 ============
- Sub Record_Count()
- Dim cn As Object '←Connectionオブジェクト
- Dim SQL As String '←SQL文
- Dim cnt As Long '←変更対象のレコード数
- Dim s As String '←接続文字列
- Set cn = CreateObject("ADODB.Connection") '←Connectionオブジェクトの生成
- s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" '←ドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & ";" '←データソース情報
- s = s & "ReadOnly=0;" '←その他の情報
- cn.Provider = "MSDASQL" '←プロバイダーをODBCに設定
- cn.ConnectionString = s '←ドライバ情報+データソース情報+その他の情報をConnectionStringプロパティに渡す
- cn.Open '←データベースに接続
- SQL = "update [db$] set St='XYZ' where DT=#2000/11/20#" '←SQL文にUpdate文を設定
- cn.Execute SQL, cnt '←SQL文を実行し、変更対象レコード数をcnt変数で取得
- MsgBox "変更対象のレコード数:" & cnt & "行" '←変更対象レコード数を表示
- cn.Close '←データベースを閉じる
- Set cn = Nothing
- End Sub
139行目「cn.Execute SQL, cnt」で、Executeメソッドの第2パラメータに指定した「Long型の変数cnt」に、変更対象となったレコード数が戻されますので、それを141行目「MsgBox "変更対象のレコード数:" & cnt & "行"」でメッセージ表示をさせています。
出力された様子は図36のようになります。
図36
SQL文は137行目の「update [db$] set St='XYZ' where DT=#2000/11/20#」ですので、DT列(3列目)が2000/11/20のものを抽出し、St列(1列目)の値をXYZに変更しています。図36のワークシートで、Dt列が「2000/11/20」なのは6~8行の「3レコード」なので、メッセージ表示も3行となります。
但し、このSQL文で「変更する以前からSt列がXYZ」だった場合でも、値が変更された事は事実なので3行と表示されます。つまり、値が変わったことを表すのでは無い事には注意が必要です。言ってみれば「Select count(*) from [db$] where DT=#2000/11/20#」を実行した時に得られる値になります。
第3パラメータ(Options)は、第1パラメータ(CommandText)に指定したものの種類を指定します。
定数 | 値 | 内容 |
---|---|---|
adCmdUnspecified or adOptionUnspecified | -1 | 種類を指定せず |
adCmdText | 1 | SQL文 |
adCmdTable | 2 | テーブル |
adCmdStoredProc | 4 | ストアドプロシージャ |
adCmdUnknown | 8 | 不明(既定) |
adAsyncExecute | 0x10(16) | 非同期実行 |
adAsyncFetch | 0x20(32) | 残り行を非同期で取得 |
adAsyncFetchNonBlocking | 0x40(64) | 取得中にブロックせず |
adExecuteNoRecords | 0x80(128) | 行を返さないコマンド |
adCmdFile | 256 | Recordsetファイル |
adCmdTableDirect | 512 | 全列が返るテーブル (ExcelシートDB、CSVファイル) |
adExecuteStream | 0x400(1024) | コマンド実行結果をストリームとして返すもの |
adExecuteRecord | 0x800(2048) | 単一行を返すもの |
既定値はadCmdUnknown(値=8)で、SQL文を指定した場合は既定(第3パラメータを省略)でも正しく判定してくれます。
なお、ACE・Jetプロバイダーの時には「adCmdTableDirect(値=512)を指定すれば、Excel・CSVでもテーブル名で接続可」でしたが、MSDASQLプロバイダーでは「ExcelとCSVでは、第1パラメータにテーブル名を指定した時には、Optionsパラメータに何を指定してもエラー」が発生してしまい、レコードの取得が出来ません。
このことから「Excel・CSVでは、テーブル名での操作は不可」となります。
またAccessでテーブル名を指定する際は、Optionsパラメータを省略する他、様々な値でもOKです。詳しくは「よりみち」を参照ください。
5.Recordsetオブジェクト
5ー1.Openメソッド(レコードセット取得)
データベース接続後は、データベースから値をレコードセットとして受け取り処理をしたり、データを変更(Insert、Update、Delete処理)したりする作業に移ります。そのレコードセットの取得やデータ変更のSQL文を実行する方法の1つとして、下記のようにRecordsetオブジェクトのOpenメソッドを使う方法があります。
Recordset.Open (Source, ActiveConnection, CursorType, LockType, Options)
このOpenメソッドを実行すると、レコードセットを取得した場合はRecordsetオブジェクトにデータ(レコードセット)が入ります。
レコードセットのOpenメソッドには、下記の5つのパラメータが設定可能です。
パラメータ | 内容 | |
---|---|---|
Source | 省略可 | ①テーブル名 ②SQL文 ③Commandオブジェクト |
ActiveConnection | 省略可 | ④Connectionオブジェクト ⑤ConnectionString文 (SourceにCommandオブジェクトを指定した場合は省略する事) |
CursorType | 省略可 | カーソルの種類(図39) |
LockType | 省略可 | ロックの種類(図40) |
Options | 省略可 | Source(第1パラメータ)の種類(図37) |
5ー1ー1.各パラメータの値
第1パラメータのSourceは、テーブル名①やSQL文②を指定します。また事前にCommandオブジェクトのCommandTextプロパティにテーブル名やSQL文をセットしておき、そのCommandオブジェクト③を第1パラメータに指定することも可能です。なお、Commandオブジェクトを指定する場合は、CommandTextプロパティにテーブル名やSQL文を格納するのと同時に、ActiveConnectionプロパティに接続中のConnectionオブジェクトを指定することが必要です。そして、下で説明する第2パラメータは必ず省略させます。
第2パラメータのActiveConnectionは、接続しているConnectionオブジェクト変数④を指定します。その他の方法として、Connectionオブジェクトの接続情報⑤を文字列で指定することも可能です。
この接続情報を文字列で指定する場合は、ドライバー情報・データベース名情報は必須です(Provider情報は、既定値がMSDASQLなので無くても大丈夫です)。なお、データベース名を登録しているのであればDSN情報のみでもOKです。
また、第1パラメータにCommandオブジェクトを指定した場合は、第2パラメータは必ず省略します。
第3パラメータのCursorTypeには、以下の定数を指定します。
定数 | 値 | 内容 |
---|---|---|
adOpenForwardOnly | 0 | 前方スクロールタイプカーソルを開く(既定) |
adOpenKeyset | 1 | キーセットカーソルを開く |
adOpenDynamic | 2 | 動的カーソルを開く |
adOpenStatic | 3 | 静的カーソルを開く |
adOpenUnspecified | -1 | カーソルを指定せず(≒既定) |
第4パラメータのLockTypeには、以下の定数を指定します。
定数 | 値 | 内容 |
---|---|---|
adLockReadOnly | 1 | 読み取り専用レコードを示す(既定) |
adLockPessimistic | 2 | 編集直後にレコードをロックする |
adLockOptimistic | 3 | Updateメソッドを呼び出すときにのみレコードをロック |
adLockBatchOptimistic | 4 | バッチ更新 |
adLockUnspecified | -1 | ロックの種類を指定せず(≒既定) |
この第3(CursorType)と第4(LockType)パラメータの設定には注意が必要です。「各パラメータの組み合わせ」で詳しく説明しますが、第1パラメータにテーブル名を指定する際に「第3と第4パラメータを省略すると、思った処理ができない」可能性があります。逆に第1パラメータにSQL文を指定すれば、大きな不具合は無さそうです。
第5パラメータのOptionsは、第1パラメータ(Source)に指定したものの種類を、図37の定数で指定します。内容はConnectionオブジェクトのExecuteメソッドの第3パラメータ、CommandオブジェクトのExecuteメソッドの第3パラメータと同じです。
第1パラメータがSQL文の場合は第5パラメータは省略でもOKですし、Accessデータベースであればテーブルの場合でも省略しても問題ありません(詳細は「よりみち」を参照下さい)。しかし、テーブル名としてExcelのシート名やCSVのファイル名を指定する事は、MSDASQLプロバイダーでは出来ません。これはadCmdTableDirect(値=512)を指定すればOKであったACE・Jetプロバイダーの場合と異なる点です。
5ー1ー2.各パラメータの組み合わせ
このRecordset.Open のパラメータの内、第1パラメータは「テーブル名」又は「SQL文」のどちらか(Commandオブジェクトでも間接的にはテーブル名かSQL文のどちらか)ですし、第5パラメータは、その第1パラメータに指定したものが何かを指定しますので一意で決まると言っても良いと思います。また第2パラメータは接続したConnectionですし、その接続情報を文字列で指定したとしても、内容的には同じです。
多くの選択が可能なのは第3パラメータ(CursorType)と第4パラメータ(LockType)で、その組み合わせが実行内容にどのように影響しているかを確かめてみたのが以下になります。
5ー1ー2ー1.Accessの場合(Openメソッドにはテーブル名を指定)
データベース対象をAccessにし、第1パラメータ(Source)にテーブル名を指定した状態で、CurorType(第3パラメータ)とLockType(第4パラメータ)の色々な組み合わせ状態を作ります。その各組み合わせで、データ取得(Select)・データ挿入(Insert)・データ変更(Update)・データ削除(Delete)のどの操作が可能かをまとめたのが図41です。LockType定数 | 値 | CursorType定数 | ||||
---|---|---|---|---|---|---|
0 (For | 1 (Key | 2 (Dyna | 3 (Sta | -1 (Unspeci | ||
adLock | 1 | S・・・ | S・・・ | S・・・ | S・・・ | S・・・ |
adLock | 2 | S[IUD] | SIUD | SIUD | SIUD | S[IUD] |
adLock | 3 | S[IUD] | SIUD | SIUD | SIUD | S[IUD] |
adLock | 4 | S([IUD]) | S(IUD) | S(IUD) | S(IUD) | S([IUD]) |
adLock | -1 | S・・・ | S・・・ | S・・・ | S・・・ | S・・・ |
「・」は処理不可
図41
まずLockTypeがadLockReadOnly(値=1:読取専用)の場合は、Select処理のみとなります。またadLockUnspecified(値=-1:指定無し)はadLockReadOnlyと同じ状態になります。
また、LockTypeがadLock
一方でadLockBatchOptimistic(値=4:バッチ更新)の場合は、IUD(=Insert・Update・Delete)を丸カッコ "( )" 付きとしていますが、注意点が2つあります。
1つ目はUpdateやDelete作業時に次のレコードに移動(=MoveNextメソッド実行時)する際、UpdateBatchでデータを確定させないと「新規取得する前に全ての行ハンドルを解放する必要があります」というエラーが発生します。これは「プロバイダーがJET・ACE」の時に説明したように、ExcelのVBA上では「バッチ処理として記憶できる容量が1レコード」である事と関係ありそうですが、詳しい事は分かりません。
2つ目は「レコードを変更した後にUpdateメソッド(書き込み処理)を実行しても、データベース本体には変更内容が保存されない」事です。バッチ処理という言葉の通り「UpdateBatch」メソッドを実行しない限り、変更内容はデータベースに保存されません。これも、プロバイダーにACE・Jetを指定した時と同じです。
またCursorTypeがadOpenForwardOnly(値=0)及びadOpenUnspecified(値=-1)の場合、IUD(=Insert・Update・Delete)を角カッコ "[ ]" 付きとしています。この組み合わせの時には、下の「よりみち」のように「使用できないデータ型」が発生してしまう事と、「処理時に他の列のデータ値の影響を受ける」ことが分かりました。
対応としては、MSDASQLプロバイダーではCursorTypeがadOpenForwardOnly(値=0)及びadOpenUnspecified(値=-1)以外のCursorTypeを使用するか、またはテーブル名では無くSQL文を使用することをお勧めします。
(CursorType=adOpenForwardOnly(値=0)での不具合) 「MSDASQLプロバイダー」+ CursorTypeが「adOpenForwardOnly(値=0)又は Unspecified(値=-1)」+「Accessテーブル名を指定」しての処理に特化して説明します。まずAccessには下図のように多くのデータ型が設定できます。 図42 (1)要注意のデータ型図42のデータ型に〇・△・×印をしてありますが、この内〇印は「問題なく処理が可能なデータ型」です。しかし△印、及び×印で示したデータ型は「注意が必要」となります。なお「レプリケーションID型」「添付ファイル型」は、Excel側からの対応方法が良く分からないので「?」印にしています。その注意点ですが、まず「△印のデータ型のみで作成されたテーブル」では、データ変更処理(=Insert・Update・Delete)時にエラーが発生します。逆に言うと、テーブルの中に「1つでも〇印のデータ型の列が存在すれば、エラーは出ない」ことになります。残念ながら、この理屈は全く分かりません。 一方×印のデータ型が入っているテーブルでは「テーブル内に〇印のデータ型列が存在していても、データ変更処理(=Insert・Update・Delete)時にエラー」が発生します。 このエラー種類は全部で4種類(データ型種で数えると7種)あり、そのエラー内容を図43にまとめました。左端の①~④は、図42内の番号と合わせてあります。
まず△印(〇印のデータ型の列が無いと、データ変更時にエラー発生)は①と②です。 データを変更しようとした場合、①のデータ型(長いテキスト型、単精度浮動小数点型、倍精度浮動小数点型、ハイパーリンク型)の列に対しては、「キーとして使用する検索可能な列がクエリに含まれていないため、クエリを更新できません」とのエラーが発生します。 また②のデータ型(OLEオブジェクト型)の列に対しては、データ変更の際に「複数ステップのOLE DBの操作でエラーが発生しました」とのエラーが発生します。 且つデータは「1文字単位の配列」となるため、通常は「貼付け先 = Recordset.Fields(1).Value」等のコードで済むところを、配列内文字列を一旦String型変数に代入する等の処理が必要となります。 次に×印(データ変更時に必ずエラー発生)は③と④です。 ③のデータ型(オートナンバー型)は、レコードを追加すれば勝手に連番を作ってくれるデータ型ですが、その機能に逆らって値を挿入する場合は「複数ステップのOLE DBの操作でエラーが発生しました」とのエラーが発生します。しかし追番を自動入力するのであれば、わざわざデータをその列に挿入する必要は無くなりますし、テーブル作成時に初期値を設定する事も可能なので、実害は少ないかと思います。 ④のデータ型(日付/時刻型)では「キャストの指定に無効な文字値が使用されました」とのエラーが発生します。この④のデータ型列が1列でも存在すれば、他列に〇印が在ろう無かろうと、エラーとなります。 (2)他列が処理内容に影響を与える上記から考えると「〇印のデータ型を1列追加」したり「Date型の代わりに、Double型を使用」すれば良いように思えます。しかし試してみると、思いもかけない結果となります。〇印のデータ列が1つのみ存在するテーブルでデータ処理(=Update・Delete)をすると、無関係なレコードも処理してしまうのです。例えば図44のような「〇印の列(BIT型)が1つ + 他が△印列(LONGTRXT型、DOUBLE型×2)のテーブル」で、Double型列の値を検索して値変更処理を行うと、〇印のBIT列の値が同じレコード(この場合だと、対象レコード(3行目)の値がFalseなので、同じFalse値の2行目のレコード)にも変更処理が及んでしまうのです。 図44 図44では対象行がFalseですが、逆に変更行のBL列値がTrueであれば、そのTrueとなっている他レコードが変更されてしまいます。もちろん、テーブルに特殊な関係性を与えている訳でもありませんし、検索列をNu列とした場合でも同じ現象が起きますので、列の並びにも無関係のようです。 なお〇印の列を複数列作ったテーブルの場合は、その「〇印の列のセット」として同じ値のレコードが処理追加対象となってしまうようです。 (3)対応案CursorTypeにどうしてもadOpenForwardOnlyを使用したい場合は、テーブルのデータ型を工夫し図42の〇印のデータ型を複数列作成する事と合わせ、列のセットとして異なる値を入れる必要が出てきます。これは結構面倒ですし、完璧ではありません。その代わりとして、オートナンバー型(COUNTER型、AUTOINCREMENT型)の列を設けて置き、そこに連番を自動入力させるようにすると、セットとしてユニークな値となるので、正しく処理が行われるようです(簡単なチェックしかしていないので、ダメな場合があるかもしれません)。 しかしこのエラーや不具合は、今のところ「MSDASQLプロバイダー」+「CursorType=adOpenForwardOnly(値=0)又は adOpenUnspecified(値=-1)」+「テーブル名を指定」の条件で発生しますので、以下の対応が良いかと思います。 ・他のCursorTypeを使用 ・SQL文で処理 なお、OLEオブジェクト型の場合でのデータが「1文字単位の配列」になる現象は、例えSQL文を指定しても変わりません。 |
この内容をプロパティ面から検証したのが図45です。Accessデータベースにテーブル名を指定してレコードセットを取得(Open)した後の、Recordsetオブジェクトのプロパティです。CursorType値とLockType値を振ってプロパティを取得し、(Access,Excel,CSVでの違いも含め)違いが有ったプロパティのみを示しています。
なおこのプロパティ値は、Accessテーブル名を指定した時とSQL文を指定した時とで、全く同じ結果となりました。
図45
この内容を図41と見比べてみると「Updatability が値7(=1(更新)+ 2(削除)+ 4(挿入)」だと、Insert・Update・Delete処理が出来るように見えますし、また「iRowsetUpdateがTrue」の時とも思えます。
しかし、SQL文を対象とした時(図46)は全ての操作が可能ですので、矛盾します。
また「LockType」が値4(=バッチ処理)の場合でも、SQL文の時(図46)には即更新されます。
このことから「プロパティ値を見ただけでは、動作内容は特定できない」ようですが、テーブルを対象に操作に限ってみれば、プロパティ値によりある程度予測ができるような気がします。逆にSQL文での実行は、このプロパティ値の制御外だとも言えます。
なお、CursorTypeが1(adOpenKeyset)または3(adOpenStatic)の時に、Bookmark値が異常に大きな値(この時のAccessテーブルのレコード数は4行)になっているのが気になりますが、今回の操作では特に異常は発生しませんでした。
5ー1ー2ー2.Accessの場合(OpenメソッドにはSQL文を指定)
次に、データベース対象をAccessに、第1パラメータ(Source)にSQL文を指定した時の状態が図46です。なお、Inset,Update,Delete文を実行する手法としては図09のように、Connection.Execute、Command.Execute、Recordset
LockType定数 | 値 | CursorType定数 | ||||
---|---|---|---|---|---|---|
0 (For | 1 (Key | 2 (Dyna | 3 (Sta | -1 (Unspeci | ||
adLock | 1 | SIUD | SIUD | SIUD | SIUD | SIUD |
adLock | 2 | SIUD | SIUD | SIUD | SIUD | SIUD |
adLock | 3 | SIUD | SIUD | SIUD | SIUD | SIUD |
adLock | 4 | SIUD | SIUD | SIUD | SIUD | SIUD |
adLock | -1 | SIUD | SIUD | SIUD | SIUD | SIUD |
図46
SQL文を指定すると、どのCursorType・LockTypeでも全ての操作が可能となります。ACE・Jetプロバイダーを使用した時には、CursorType=1(Keyset) × LockType=1(ReadOnly) の時にはUpdate処理・Delete処理が出来ませんでしたが、MSDASQLでは可能な様です。
またLockType=4(バッチ処理)の場合、図41(テーブル名指定)ではUpdateBatchメソッドを実行しない限り、データベースに変更内容が反映されませんでしたが、図46(SQL文指定)ではそのまま反映されます。
この検証としてレコードセットのプロパティ値を調べてみた結果は、テーブル指定の図45と全く一緒でした。
結論として、SQL文を使う場合は「実行可不可をあまり気にせずに、ロックの種類を検討できる」と言えるのかもしれません。
5ー1ー2ー3.ExcelシートDBの場合(OpenメソッドにはSQL文を指定)
まずExcelをデータベースとした場合、テーブル名(=ワークシート名+$印)を指定しての処理は「MSDASQLプロバイダーでは不可」となります(Connection.Executeメソッド参照)。従って「Excelをデータベースにする際、MSDASQLプロバイダーではSQL文を指定して処理」する必要があります。Excelのシートをデータベースにし、第1パラメータ(Source)にSQL文を指定した時の状態が図47です。
LockType定数 | 値 | CursorType定数 | ||||
---|---|---|---|---|---|---|
0 (For | 1 (Key | 2 (Dyna | 3 (Sta | -1 (Unspeci | ||
adLock | 1 | SIU | SIU | SIU | SIU | SIU |
adLock | 2 | SIU | SIU | SIU | SIU | SIU |
adLock | 3 | SIU | SIU | SIU | SIU | SIU |
adLock | 4 | SIU | SIU | SIU | SIU | SIU |
adLock | -1 | SIU | SIU | SIU | SIU | SIU |
図47
この結果から、SQL文を使うと「LockType × CursorTypeの全組み合わせで処理が可能(もちろんDelete処理は不可)」であることが分かります。これをプロパティ値で確認してみたのが図48になります。
図48
図48は値の異なるプロパティのみを比較しているので、図47のように全て同じ結果となるものへの究明には意味が無いかもしれません。それでもUpdatability等が異なるのは、SQL文がこのプロパティ値を超えて直接データベースを操作しているという事を表しているのかもしれません。
5ー1ー2ー4.CSVの場合(OpenメソッドにはSQL文を指定)
CSVファイルをデータベースとした場合もExcelの時と同様に、テーブル名(=ファイル名)を指定しての処理は「MSDASQLプロバイダーでは不可」となります(Connection.Executeメソッド参照)。従って「CSVをデータベースにする際、MSDASQLプロバイダーではSQL文を指定して処理」する必要があります。CSVファイルに対して、第1パラメータにSQL文を指定した時の実行可否を表したのが図49です。
LockType定数 | 値 | CursorType定数 | ||||
---|---|---|---|---|---|---|
0 (For | 1 (Key | 2 (Dyna | 3 (Sta | -1 (Unspeci | ||
adLock | 1 | SI | SI | SI | SI | SI |
adLock | 2 | SI | SI | SI | SI | SI |
adLock | 3 | SI | SI | SI | SI | SI |
adLock | 4 | SI | SI | SI | SI | SI |
adLock | -1 | SI | SI | SI | SI | SI |
図49
CSVファイルに対しては、元々Select操作とInsert操作しか出来ませんが、全てのCursorTypeとLockTypeの組み合わせで両操作が出来ます。この時のプロパティ値を図50に示します。
図50
CSVのプロパティ値は、Excel(図48)のプロパティ値と全く同じでした。
6.Commandオブジェクト
Commandオブジェクトには、複数のプロパティやメソッドが存在しますが、ここではコマンドの格納やコマンドの実行に必要な「ActiveConnection」プロパティ、「CommandText」プロパティ、「Execute」メソッドの3種を説明します。6ー1.ActiveConnectionプロパティ(データベースとの結び付け)
まず生成したCommandオブジェクトが、どの「データベース接続」に属しているかを指定するのがActiveConnectionプロパティです。構文としては、下記のように「接続中のConnectionオブジェクト」を指定します。Command.ActiveConnection = 接続中のConnectionオブジェクト
なおConnectionオブジェクトの代わりに、Provider名・DBQ名・Driver名を含めた接続文字列をActiveConnectionに指定してもOKです(なおProvider名の既定値はMSDASQLですので、省略も可です)。Microsoftのサイトでは、「接続が閉じている時に文字列指定」との説明がありますが、試してみると接続中でもOKでした。
6ー2.CommandTextプロパティ(実行コマンドの格納)
コマンドをCommandオブジェクトで実行する場合にも、またCommandオブジェクトに格納後Recordset.Openでレコードセットを取得する場合にも、「実行コマンドはCommandTextプロパティに代入」します。構文は以下の通りです。Command.CommandText = 実行コマンド(String型)
実行コマンドは、今回ではデータベースの「テーブル名」や「SQL文」です。
6ー3.Executeメソッド(コマンドの実行)
Commandオブジェクトでコマンドを実行するには、Executeメソッドを使用します。構文は以下となります。Set Recordsetオブジェクト = Command.Execute ( RecordsAffected, Parameters, Options )
このExecuteメソッドを実行する前準備として、「ActiveConnectionプロパティで接続データベースへ紐付け」をし、「CommandTextプロパティに、実行するテーブル名やSQL文を代入」しておく必要があります。
またRecordsetオブジェクトとして受け取る場面は、CommandTextプロパティに「テーブル名」や「SQL文のSelect文」を指定し、戻ったレコードセットに対して処理を行う時だと思いますが、この時の戻り値(Recordsetオブジェクト)のデータは「読み取り専用」ですので注意が必要です。これは、ConnectionオブジェクトのExecuteの時と同じです。
なお第1パラメータに「InsertやUpdate・DeleteのSQL文を指定」した場合は、戻り値を操作する訳では無いので、追加・変更・削除処理は可能です(Excelは削除不可、CSVは変更・削除不可 である事は変わりません)。
このようなInsert文等を指定した時は、変更を目的としたレコードセットを受け取る必要が無いので、以下のように戻り値を受け取らない形で実行します。
Command.Execute ( RecordsAffected, Parameters, Options )
Executeメソッドに指定する3つのパラメータは以下の内容になります。全て省略可です。
パラメータ | 内容 | |
---|---|---|
RecordsAffected | 省略可 | Long型の変数に、変更レコード数を戻す |
Parameters | 省略可 | パラメータクエリ(SQL文)に渡す パラメータ値の配列 |
Options | 省略可 | CommandTextの種類 (図37) |
第1パラメータのRecordsAffectedは、Long型変数を引数として与えておくことで、Insert・Update・Delete処理で影響を与えたレコード数を戻してくれるものです。使い方は図35と同じです。なおSelect文でも使用は出来ますが、選択したレコード数を戻してくれる訳ではありません。
第2パラメータのParametersは、CommandTextにパラメータクエリ(≒変数をSQL文に組み込んだようなもの)を指定した際、そのパラメータ値を配列として指定するものです(今回は、説明を省略します)。
第3パラメータ(Options)は、第1パラメータに指定したものの種類を図37のように指定します。内容はConnectionオブジェクトのExecuteメソッドの第3パラメータ、RecordsetオブジェクトのOpenメソッドの第5パラメータと同じです。
(Optionsパラメータの指定方法) MSDASQLプロバイダーでは、ExcelやCSVでのテーブル名指定でのデータ取得はできず、SQL文指定のみとなります。これは、図37の所で説明したConnectionオブジェクトやRecordsetオブジェクトだけでなく、Commandオブジェクトに対しても同じです。 理由は、これらオブジェクトのExecuteメソッドやOpenメソッドのOptionsパラメータにadCmdTableDirect(値=512)を指定しても、MSDASQLプロバイダー環境ではExcelやCSVのテーブル名指定ではエラーになってしまう為です。 一方Accessでは、テーブル名指定・SQL文指定のどちらでもデータ取得が可能ですが、その際にOptionsパラメータの指定には注意する必要があります。 図52は、各オブジェクトでの実行メソッドに於いて、Optionsパラメータを振って実行可能か否かを確認したものです。
Optionsパラメータを省略(図52のadCmdUnknown(値=8))すればテーブル名指定・SQL文指定のどちらでもOKですが、他の値を指定した場合にはエラーが出てしまう場合があります。 対象がテーブル名かSQL文かで分けていますので、adCmdText(値=1)・adCmdTable(値=2)・adCmdTableDirect(値=512)で〇×が入れ替わるのは理解できます。しかしテーブル名指定時でCommand.Executeの時には、赤字の×印のように「OptionsパラメータにadCmdTableDirect(値=512)を指定するとエラー」が出ますので御注意ください。 今回の範囲では、それ以外には違いは出ませんでしたが、ここで説明した以外の機能でも「Commandオブジェクトだけは特殊」という事があるかもしれませんので、注意が必要と思います。 |
6ー4.Commandオブジェクトの使用例
6ー4ー1.実行コマンドの格納
Commandオブジェクトを使用してデータベース操作する場面は2種類あります。1つ目は、実行するコマンド(テーブル名、またはSQL文)をCommand.CommandTextプロパティに格納した後「Recordset.Openの第1パラメータにCommandオブジェクトを指定」することでレコードセットを取得したり、変更のSQL文を実行したりする場面です。
- '========== ⇩(8) Commandオブジェクトに実行コマンドを格納 ============
- Dim cn As Object '←実行時バインディングのConnectionオブジェクト
- Dim rs As Object '←実行時バインディングのRecordsetオブジェクト
- Dim cmd As Object '←実行時バインディングのCommandオブジェクト
- Dim s As String '←接続文字列
- Set cn = CreateObject("ADODB.Connection") '←Connectionオブジェクトの生成
- Set rs = CreateObject("ADODB.Recordset") '←Recordsetオブジェクトの生成
- Set cmd = CreateObject("ADODB.Command") '←Commandオブジェクトの生成
- s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←ドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←データソース情報
- cn.Provider = "MSDASQL" '←プロバイダー設定
- cn.ConnectionString = s '←ドライバー+DB設定
- cn.Open '←データベースに接続
- cmd.ActiveConnection = cn '←接続条件をCommandオブジェクトに設定
- cmd.CommandText = "Select * from TestTable" '←実行コマンドをCommandオブジェクトに設定
- rs.Open cmd '←コマンドを格納したCommandを使って実行
- (処理)
168行目「cmd.ActiveConnection = cn」で、データベース接続条件を取り込みます。
169行目「cmd.CommandText = "Select * from TestTable"」で実行コマンドをCommandTextに格納します。
171行目「rs.Open cmd」で、そのSQL文をRecordsetオブジェクトから実行します。
一般的なRecordset.Openの使い方は「rs.Open SQL文 , cn」のように、第1パラメータにSQL文やテーブル名を指定し、第2パラメータには接続情報のあるConnectionオブジェクトを指定しますが、Commandオブジェクトを使った171行目では、第2パラメータを省略します。
これは、第1パラメータに指定したCommandオブジェクトは、CommandTextプロパティにSQL文やテーブルを指定(169行目)し、ActiveConnectionプロパティに接続情報を指定(168行目)したからですが、第2パラメータを更に重複設定するとエラーが出ます。つまり「省略しないとエラー」との説明の方が正しいかもしれません
と言って、ActiveConnectionプロパティへの指定を省略し「rs.Open cmd, cn」とするとエラーが出ます。「CommandオブジェクトのCommandTextとActiveConnectionはセットで指定」する必要があります。
なお、図53はSelect文でしたが、CommandTextプロパティにテーブル名を指定しても同じです。またデータ変更用のSQL文を指定した場合は、171行目の実行でデータが変更されます。
6ー4ー2.コマンドの実行
2つ目は、実行コマンド(=テーブル名、SQL文)を指定した後、CommandオブジェクトのExecuteメソッドで実行をする場面です。その際、SQL文がSelect文であったりテーブル名であれば、ExecuteメソッドがRecordsetオブジェクトを戻してきますので、レコードセットとして取得します。またデータ変更のSQL文(Insert・Update・Delete文)であれば、データ変更を実行します。- '========== ⇩(9) Commandオブジェクトで実行 ============
- Dim cn As Object '←実行時バインディングのConnectionオブジェクト
- Dim rs As Object '←実行時バインディングのRecordsetオブジェクト
- Dim cmd As Object '←実行時バインディングのCommandオブジェクト
- Dim s As String '←接続文字列
- Set cn = CreateObject("ADODB.Connection") '←Connectionオブジェクトの生成
- Set cmd = CreateObject("ADODB.Command") '←Commandオブジェクトの生成
- s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←ドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←データソース情報
- cn.Provider = "MSDASQL" '←プロバイダー設定
- cn.ConnectionString = s '←ドライバー+DB設定
- cn.Open '←データベースに接続
- cmd.ActiveConnection = cn '←接続条件をCommandオブジェクトに設定
- cmd.CommandText = "Select * from TestTable" '←実行コマンドをCommandオブジェクトに設定
- Set rs = cmd.Execute '←実行コマンドを実行
- (処理)
197行目「cmd.ActiveConnection = cn」で、データベース接続条件を取り込みます。
198行目「cmd.CommandText = "Select * from TestTable"」で実行コマンドをCommandTextに格納します。
199行目「Set rs = cmd.Execute」の右辺で、そのコマンドをCommandオブジェクトで実行し、戻り値であるRecordsetオブジェクトを変数rsで受け取り、処理をします。
なおデータ変更を伴うSQL文の場合は、変数で受ける必要は無いので、199行目は右辺のみでOKです。
7.データベースに接続する為のコード例
図09でも紹介した通り、データベースに接続・操作する方法はいくつかあります。図55はその再掲ですが、下半分(薄黄色のエリア)に、MSDASQLプロバイダーを使用した時の、各手法での可能な操作(Select、Insert、Update、Delete)をまとめました。一般的には「ExcelはDeleteが出来ない」「CSVはUpdateとDeleteが不可」などと言われていますが、接続・操作の方法でも変わってくることが分かると思います。なお実行時に指定するパラメータによっては、更に不可の操作もあるのでご注意下さい。
図55
12種類と多そうに見えますが、基本的には以下の4種類で、実行するもの(テーブル、SQL文)が変わるだけです。しかも3と4は、Commandオブジェクトを経由するか否かの違いですので、3種と言っても良いくらいです。
1.「Connection.Open(DB接続)」→「Connection.Execute(実行)」→(「処理」)
2.「Connection.Open(DB接続)」→「Command.Execute(実行)」→(「処理」)
3.「Connection.Open(DB接続)」→「Commandへコマンド格納」→「Recordset.Open(実行)」→(「処理」)
4.「Connection.Open(DB接続)」→「Recordset.Open(実行)」→(「処理」)
ここでは図55に示す12種類の実際のコードを紹介していきます。
なおコードは、主に「Excel」について説明していきますが、見え消しにしてある「Accessのコード」「CSVのコード」と切り替えれば動作確認が出来るようにしています。(MSDASQLプロバイダーでは、テーブル名を指定した場合はAccessしか操作できませんので、図55のNo.1~4についてはAccessのみでの説明になります。)
今回のコード例では、データベースとして「Access」「Excel」「CSV(カンマ区切りテキスト)」を扱います。そのデータは、以下のような形の「4列×4行」としました。St、Nu、Dt、BLが列名になります。Excel、CSVも先頭行は列名行としています。
St | Nu | Dt | BL |
---|---|---|---|
"abc" | 123 | 2023/1/2 | True |
"def" | 123 | 2023/2/2 | False |
"abc" | 456 | 2023/3/2 | False |
"def" | 456 | 2023/4/2 | True |
なお扱っているデータベースですが、Excelは本サンプルファイル(its-043.xlsm)のワークシート「DB」、Accessは添付のits-041.accdb(作成方法はDAOでAccess・Excel・CSV等へ接続・操作を参照下さい)、CSVは添付のits-041.csvです。
なおAccessは、よりみちで説明した通り「テーブル名指定 + CursorType=adOpenForwardOnly(値=0)では、Date型はNG」ですし「他列の値により間違った処理」がされてしまいますので、以下のサンプルコードでは CursorType = adOpenKeyset(値=1)を使用しています。
7ー1.テーブルを操作
データベースに接続し、「テーブル」を操作するコードとして4種類を以下で紹介します。なおMSDASQLプロバイダーでは「ExcelやCSVファイルをテーブル名指定で操作する事は不可」ですので、Accessのみの接続・操作となります。7ー1ー1.Connectionでテーブル名を実行し、レコードセット取得後に処理
図55のNo.1のコードは、以下のようになります。- '========== ⇩(10) Connectionでテーブル名を実行しレコードセットを取得 ============
- Sub Pattern01()
- Dim cn As Object '←Connectionオブジェクト
- Dim rs As Object '←Recordsetオブジェクト
- Dim SQL As String '←テーブル名
- Dim s As String '←接続文字列
- Dim i As Integer '←レコードの行位置
- Set cn = CreateObject("ADODB.Connection")
- s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←ドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←データソース情報
- cn.Provider = "MSDASQL" '←プロバイダー設定
- cn.connectionstring = s '←ドライバー+データソース情報設定
- cn.Open
- SQL = "TestTable" '←操作するテーブル名
- Set rs = cn.Execute(SQL) '←レコードセットを取得
- With Sheet1.Range("B2")
- .CurrentRegion.ClearContents
- Do While Not rs.EOF
- .Offset(i, 0) = rs.Fields(0).Value
- .Offset(i, 1) = rs.Fields(1).Value
- .Offset(i, 2) = rs.Fields(2).Value
- .Offset(i, 3) = rs.Fields(3).Value
- rs.MoveNext
- i = i + 1
- Loop
- End With
- rs.Close
- cn.Close
- Set rs = Nothing
- Set cn = Nothing
- End Sub
218行目「Set cn = CreateObject("ADODB.Connection")」で、ADOのConnectionオブジェクトを生成します。
220行目「s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};"」でドライバー情報を文字列にし、221行目「s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;"」でデータソース情報(≒Accessファイル名)を追加します。
223行目「cn.Provider = "MSDASQL"」で、MSDASQLプロバイダーを設定します。なおADOの既定プロバイダーはMSDASQLですので、省略してもOKです。
224行目「cn.connectionstring = s」で、220~221行目で準備した接続情報文字列をConnectionオブジェクトのconnectionstringプロパティに指定します。
226行目「cn.Open」で、Accessデータベースに接続します。
228行目「SQL = "TestTable"」で、実行するテーブル名を変数SQLに格納します。
229行目「Set rs = cn.Execute(SQL)」の右辺では、ConnectionオブジェクトのExecuteメソッドでテーブル名を実行します。
この実行によりテーブルの全データ(レコードセット)が取得できますので、左辺の変数rsに代入します。なお、この段階では、レコードセットのカーソル(操作できる行位置)は、先頭行にあります。
231~241行目では、取得したレコードセットの全データをワークシート上に書き出しています。
231行目「With Sheet1.Range("B2")」では、シートへのデータ書き出しの基準点を決めています。
232行目「.CurrentRegion.ClearContents」は、その基準点を含むエリアに書かれていたデータをクリアします。
233行目「Do While Not rs.EOF」では、レコードセットの終端が来るまで234~239行目を回します。
234行目「.Offset(i, 0) = rs.Fields(0).Value」は、レコードセットの1列目のデータをシートの1列目に書き込みます。
235~237行目も同様に、2列目・3列目・4列目と書き込みます。
238行目「rs.MoveNext」では、レコードセットのカーソル位置を次の行に移動します。
239行目「i = i + 1」では、シート上の書き込み位置を1つ下に移動させています。
233行目では「Not rs.EOF」となっていますので、データ処理が全て完了し「rs.EOF = True」が成立すればDo~Loopを抜け出します。243行目「rs.Close」でレコードセットを閉じ、244行目「cn.Close」でデータベースとの接続を終了させます。
7ー1ー2.Commandでテーブル名を実行し、レコードセット取得後に処理
図55のNo.2のコードは、以下のようになります。- '========== ⇩(11) Commandでテーブル名を実行しレコードセット取得 ============
- Sub Pattern02()
- Dim cn As Object '←Connectionオブジェクト
- Dim rs As Object '←Recordsetオブジェクト
- Dim cmd As Object '←Commandオブジェクト
- Dim SQL As String '←テーブル名
- Dim s As String '←接続文字列
- Dim i As Integer '←レコードの行位置
- Set cn = CreateObject("ADODB.Connection")
- Set cmd = CreateObject("ADODB.Command")
- s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←ドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←データソース情報
- cn.Provider = "MSDASQL" '←プロバイダー設定
- cn.connectionstring = s '←ドライバー+データソース情報設定
- cn.Open
- SQL = "TestTable" '←操作するテーブル名
- cmd.ActiveConnection = cn
- cmd.CommandText = SQL
- Set rs = cmd.Execute
- With Sheet1.Range("B2")
- .CurrentRegion.ClearContents
- Do While Not rs.EOF
- .Offset(i, 0) = rs.Fields(0).Value
- .Offset(i, 1) = rs.Fields(1).Value
- .Offset(i, 2) = rs.Fields(2).Value
- .Offset(i, 3) = rs.Fields(3).Value
- rs.MoveNext
- i = i + 1
- Loop
- End With
- rs.Close
- cn.Close
- Set rs = Nothing
- Set cmd = Nothing
- Set cn = Nothing
- End Sub
269行目「Set cn = CreateObject("ADODB.Connection")」でConnectionオブジェクトを生成し、270行目「Set cmd = CreateObject("ADODB.Command")」でCommandオブジェクトを生成します。
272行目「s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};"」でドライバー情報を文字列にし、273行目「s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;"」でデータソース情報(≒Accessファイル名)を追加します。
275行目「cn.Provider = "MSDASQL"」で、MSDASQLプロバイダーを設定します。なおADOの既定プロバイダーはMSDASQLですので、省略してもOKです。
276行目「cn.connectionstring = s」で、272~273行目で準備した接続情報文字列をConnectionオブジェクトのconnectionstringプロパティに指定します。
278行目「cn.Open」で、Accessデータベースに接続します。
280行目「SQL = "TestTable"」で、Accessのテーブル名を変数SQLに代入します。
281行目「cmd.ActiveConnection = cn」は、接続中のConnectionオブジェクトをCommandオブジェクトのActiveConnectionに指定し、ConnectionとCommandを結び付けています。
282行目「cmd.CommandText = SQL」では、CommandオブジェクトのCommandTextにAccessテーブル名を指定しています。
284行目「Set rs = cmd.Execute」の右辺では、CommandオブジェクトのExecuteメソッドを実行し、Accessのテーブルを開いてレコードセットにし、左辺の変数rsに代入しています。
レコードセットを取得した後は図57と全く同じです。286~296行目では、取得したレコードセットをDo~Loopで回しながら全データをシート上に書き出しています。
7ー1ー3.Commandにテーブル名を格納後Recordset実行し、レコードセット取得後に処理
図55のNo.3のコードは、以下のようになります。- '========== ⇩(12) Commandにテーブル名を格納後Recordset実行しレコードセット取得 ============
- Sub Pattern03()
- Dim cn As Object '←Connectionオブジェクト
- Dim rs As Object '←Recordsetオブジェクト
- Dim cmd As Object '←Commandオブジェクト
- Dim SQL As String '←テーブル名
- Dim s As String '←接続文字列
- Dim i As Integer '←レコードの行位置
- Set cn = CreateObject("ADODB.Connection")
- Set rs = CreateObject("ADODB.Recordset")
- Set cmd = CreateObject("ADODB.Command")
- s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←ドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←データソース情報
- cn.Provider = "MSDASQL" '←プロバイダー設定
- cn.connectionstring = s '←ドライバー+データソース情報設定
- cn.Open
- SQL = "TestTable" '←操作するテーブル名
- cmd.ActiveConnection = cn
- cmd.CommandText = SQL
- rs.Open cmd, , 1, 2
- GoTo Sel 'Sel,Ins,Upd,Del
- Sel:
- With Sheet1.Range("B2")
- .CurrentRegion.ClearContents
- Do While Not rs.EOF
- .Offset(i, 0) = rs.Fields(0).Value
- .Offset(i, 1) = rs.Fields(1).Value
- .Offset(i, 2) = rs.Fields(2).Value
- .Offset(i, 3) = rs.Fields(3).Value
- rs.MoveNext
- i = i + 1
- Loop
- End With
- GoTo En
- Ins:
- rs.AddNew
- rs.Fields(0) = "PQR"
- rs.Fields(1) = 897
- rs.Fields(2) = #11/20/2000#
- rs.Fields(3) = True
- rs.Update
' rs.UpdateBatch- GoTo En
- Upd:
- Do While Not rs.EOF
- If CDate(rs.Fields(2).Value) = #11/20/2000# Then
- rs.Fields(0) = "XYZ"
- rs.Update
' rs.UpdateBatch- End If
- rs.MoveNext
- Loop
- GoTo En
- Del:
- Do While Not rs.EOF
- If CDate(rs.Fields(2).Value) = #11/20/2000# Then
- rs.Delete
' rs.UpdateBatch- End If
- rs.MoveNext
- Loop
- En:
- rs.Close
- cn.Close
- Set rs = Nothing
- Set cmd = Nothing
- Set cn = Nothing
- End Sub
319行目「Set cn = CreateObject("ADODB.Connection")」でConnectionオブジェクトを生成、320行目「Set rs = CreateObject("ADODB.Recordset")」でRecordsetオブジェクトを生成、321行目「Set cmd = CreateObject
323行目「s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};"」でドライバー情報を文字列にし、324行目「s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;"」でデータソース情報(≒Accessファイル名)を追加します。
326行目「cn.Provider = "MSDASQL"」で、MSDASQLプロバイダーを設定します。なおADOの既定プロバイダーはMSDASQLですので、省略してもOKです。
327行目「cn.connectionstring = s」で、323~324行目で準備した接続情報文字列をConnectionオブジェクトのconnectionstringプロパティに指定します。
329行目「cn.Open」で、Accessデータベースに接続します。
331行目「SQL = "TestTable"」で、Accessのテーブル名を変数SQLに代入します。
332行目「cmd.ActiveConnection = cn」は、接続中のConnectionオブジェクトをCommandオブジェクトのActiveConnectionプロパティに指定し、ConnectionとCommandを結び付けています。
333行目「cmd.CommandText = SQL」では、CommandオブジェクトのCommandTextプロパティにAccessテーブル名を指定しています。
335行目「rs.Open cmd, , 1, 2」では、RecordsetオブジェクトのOpenメソッドを実行し、レコードセットを取得しています。パラメータとしては、第1パラメータにCommandオブジェクトを指定するのと同時に、第2パラメータは省略させます。
第3・第4パラメータは、各パラメータの組み合わせで説明した通り「テーブルのデータ型に制限が無く、正しくデータ変更が行われるパラメータ」且つ「Updateメソッドでデータベースへの変更が可となるパラメータ」を選択します。ここでは第3パラメータ(CursorType)にadOpenKeyset(値=1)を、第4パラメータ(LockType)にadLockPessimistic(値=2)を指定しています。
なお第3パラメータにadOpenForwardOnly(値=0)又は adOpenUnspecified(値=-1)を選択してしまうと、正しく変更・削除処理が出来なくなる可能性があるため御注意下さい。また第4パラメータにadLockBatchOptimistic(値=4)を選択する場合は、データ追加・変更・削除時にRecordset.Updateメソッドを実行させてもデータベース更新が完了しませんので、Recordset.UpdateBatchメソッドを使用する必要があります。
335行目によりレコードセットが得られたら、337~384行目でデータ処理をします。図59では4種の処理を337行目「GoTo Sel」で分岐させています。Selの部分を「Sel,Ins,Upd,Del」の4種で置き換える事で、Select操作・Insert操作・Update操作・Delete操作にジャンプさせています。
まずSelect処理は340~350行目です。内容は図57・図58と全く同じで、Do~Loopを使いレコードセットの終端になるまで繰り返し、4列のデータをワークシートに書き込んでいます。
Insert処理は355~361行目です。まず355行目「rs.AddNew」で新たなレコードを作成します。カーソルは、この新たに作ったレコードの位置になります。
356行目「rs.Fields(0) = "PQR"」では、1列目に"PQR"という文字列をセットしています。357~359行目も同様に2~4列目にデータをセットしています。
各列へのセットが完了したら360行目「rs.Update」でデータベースを更新します。335行目のRecordset.Openの第4パラメータにadLockBatchOptimistic(値=4)を指定する場合は、データベースへの書き換えを実行するために、360行目「rs.Update」の代わりに361行目「rs.UpdateBatch」を実行させます。なお360行目と361行目を重複実行させても問題はありません。
Update処理は366~373行目です。Do~Loopで回しながら372行目「rs.MoveNext」で行を移動させ、全行を走査します。367行目「If CDate(rs.Fields(2).Value) = #11/20/2000# Then」で、3列目のデータが2000年11月20日のものを探し出し、見つかったら368行目「rs.Fields(0) = "XYZ"」で1列目のデータをXYZに書き換えます。
書き換えが終わったら、372行目の「rs.MoveNext」でカーソルが移動してしまう前に、369行目「rs.Update」でデータベースを更新します。335行目のRecordset.Openの第4パラメータにadLockBatchOptimistic(値=4)を指定する場合は、データベースへの書き換えを実行するために、369行目「rs.Update」の代わりに370行目「rs.UpdateBatch」を実行させます。
Delete処理は378~384行目です。Do~Loopで回しながら383行目「rs.MoveNext」で行を移動させ、全行を走査します。379行目「If CDate(rs.Fields(2).Value) = #11/20/2000# Then」で、3列目のデータが2000年11月20日のものを探し出し、見つかったら380行目「rs.Delete」でその行を削除します。
Delete時は、Updateメソッドを実行しないでも良いようですが、335行目のRecordset.Openの第4パラメータにadLockBatchOptimistic(値=4)を指定する場合は、381行目「rs.UpdateBatch」が必要となります。
レコードセットの処理が完了したら、387行目「rs.Close」でレコードセットを閉じ、388行目「cn.Close」で、データベースとの接続を切ります。
7ー1ー4.Recordsetでテーブル名を実行し、レコードセット取得後に処理
図55のNo.4のコードは、以下のようになります。- '========== ⇩(13) Recordsetでテーブル名を実行しレコードセット取得 ============
- Sub Pattern04()
- Dim cn As Object '←Connectionオブジェクト
- Dim rs As Object '←Recordsetオブジェクト
- Dim SQL As String '←テーブル名
- Dim s As String '←接続文字列
- Dim i As Integer '←レコードの行位置
- Set cn = CreateObject("ADODB.Connection")
- Set rs = CreateObject("ADODB.Recordset")
- s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←ドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←データソース情報
- cn.Provider = "MSDASQL" '←プロバイダー設定
- cn.connectionstring = s '←ドライバー+データソース情報設定
- cn.Open
- SQL = "TestTable" '←操作するテーブル名
- rs.Open SQL, cn, 1, 2
- GoTo Sel 'Sel,Ins,Upd,Del ←Excel × Tableでは、Update処理・Delete処理はエラーが出ます。
- Sel:
- With Sheet1.Range("B2")
- .CurrentRegion.ClearContents
- Do While Not rs.EOF
- .Offset(i, 0) = rs.Fields(0).Value
- .Offset(i, 1) = rs.Fields(1).Value
- .Offset(i, 2) = rs.Fields(2).Value
- .Offset(i, 3) = rs.Fields(3).Value
- rs.MoveNext
- i = i + 1
- Loop
- End With
- GoTo En
- Ins:
- rs.AddNew
- rs.Fields(0) = "PQR"
- rs.Fields(1) = 897
- rs.Fields(2) = #11/20/2000#
- rs.Fields(3) = True
- rs.Update
' rs.UpdateBatch- GoTo En
- Upd:
- Do While Not rs.EOF
- If CDate(rs.Fields(2).Value) = #11/20/2000# Then
- rs.Fields(0) = "XYZ"
- rs.Update
' rs.UpdateBatch- End If
- rs.MoveNext
- Loop
- GoTo En
- Del:
- Do While Not rs.EOF
- If CDate(rs.Fields(2).Value) = #11/20/2000# Then
- rs.Delete
' rs.UpdateBatch- End If
- rs.MoveNext
- Loop
- En:
- rs.Close
- cn.Close
- Set rs = Nothing
- Set cn = Nothing
- End Sub
408行目「Set cn = CreateObject("ADODB.Connection")」で、Connectionオブジェクトを生成します。
409行目「Set rs = CreateObject("ADODB.Recordset")」で、Recordsetオブジェクトを生成します。
411行目「s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};"」でドライバー情報を文字列にし、412行目「s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;"」でデータソース情報(≒Accessファイル名)を追加します。
414行目「cn.Provider = "MSDASQL"」で、MSDASQLプロバイダーを設定します。なおADOの既定プロバイダーはMSDASQLですので、省略してもOKです。
415行目「cn.connectionstring = s」で、411~412行目で準備した接続情報文字列をConnectionオブジェクトのconnectionstringプロパティに指定します。
417行目「cn.Open」で、Accessデータベースに接続します。
419行目「SQL = "TestTable"」で、Accessのテーブル名を変数SQLに代入します。
421行目「rs.Open SQL, cn, 1, 2」では、RecordsetオブジェクトのOpenメソッドを実行し、レコードセットを取得しています。パラメータとしては、第1パラメータに419行目でテーブル名を代入した変数SQLを、第2パラメータには接続中のConnectionオブジェクト(変数cn)を指定します。
第3・第4パラメータは、各パラメータの組み合わせで説明した通り「テーブルのデータ型に制限が無く、正しくデータ変更が行われるパラメータ」且つ「Updateメソッドでデータベースへの変更が可となるパラメータ」を選択します。ここでは第3パラメータ(CursorType)にadOpenKeyset(値=1)を、第4パラメータ(LockType)にadLockPessimistic(値=2)を指定しています。
なお第3パラメータにadOpenForwardOnly(値=0)又は adOpenUnspecified(値=-1)を選択してしまうと、正しく変更・削除処理が出来なくなる可能性があるため御注意下さい。また第4パラメータにadLockBatchOptimistic(値=4)を選択する場合は、データ追加・変更・削除時にRecordset.Updateメソッドを実行させてもデータベース更新が完了しませんので、Recordset.UpdateBatchメソッドを使用する必要があります。
421行目によりレコードセットが得られたら、423~471行目でデータ処理をします。図60では4種の処理を423行目「GoTo Sel」で分岐させています。Selの部分を「Sel,Ins,Upd,Del」の4種で置き換える事で、Select操作・Insert操作・Update操作・Delete操作にジャンプさせています。
まずSelect処理は427~437行目です。Do~Loopを使いレコードセットの終端になるまで繰り返し、4列のデータをワークシートに書き込んでいます。
Insert処理は442~448行目です。442行目「rs.AddNew」で新たなレコードを作成し、443行目「rs.Fields(0) = "PQR"」で1列目に"PQR"という文字列をセットしています。444~446行目も同様に2~4列目にデータをセットしています。
各列にセットが完了したら447行目「rs.Update」でデータベースを更新します。
Recordset.Openの第4パラメータにadLockBatchOptimistic(値=4)を指定する場合は、データベースへの書き換えを実行するために、448行目「rs.UpdateBatch」を追加実行させます。
Update処理は453~460行目です。Do~Loopで回しながら459行目「rs.MoveNext」で行を移動させ、レコードセットの終端になるまで全行を走査します。454行目「If CDate(rs.Fields(2).Value) = #11/20/2000# Then」で、3列目のデータが2000年11月20日のものを探し出し、見つかったら455行目「rs.Fields(0) = "XYZ"」で1列目のデータをXYZに書き換えます。
書き換えが終わったら、459行目の「rs.MoveNext」でカーソルが移動してしまう前に、456行目「rs.Update」でデータベースを更新します。Recordset.Openの第4パラメータにadLockBatchOptimistic(値=4)を指定する場合は、データベースへの書き換えを実行するため、「rs.Update」の代わりに457行目「rs.UpdateBatch」を実行させます。
Delete処理は465~471行目です。Do~Loopで回しながら470行目「rs.MoveNext」で行を移動させ、レコードセットの終端になるまで全行を走査します。466行目「If CDate(rs.Fields(2).Value) = #11/20/2000# Then」で、3列目のデータが2000年11月20日のものを探し出し、見つかったら467行目「rs.Delete」でその行を削除します。
Delete時は、Updateメソッドを実行しないでも良いようですが、Recordset.Openの第4パラメータにadLockBatchOptimistic(値=4)を指定する場合は、468行目「rs.UpdateBatch」が必要となります。
レコードセットの処理が完了したら、474行目「rs.Close」でレコードセットを閉じ、475行目「cn.Close」でデータベースとの接続を切ります。
7ー2.SQL(Select)文で操作
データベースに接続し「SelectのSQL文」を操作するコードを以下で紹介します。なお、Excelのシートデータベースについて説明しますが、以下のようにコードを切り替えることで、データベースをAccess・CSVに切り替えることが出来ます。丸番号は、図62・図63・図64・図65で同じにしてあります。
ドライバ(Driver=) | データベース(DBQ=) | SQL文内のテーブル | |
---|---|---|---|
Access | ① {Microsoft Access Driver (*.mdb, *.accdb)} | ④パス名+ファイル名 ThisWorkbook.Path & "¥" & "its-041.accdb" | ⑦テーブル名 TestTable |
Excel | ② {Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)} | ⑤パス名+ファイル名 ThisWorkbook.Path & "¥" & ThisWorkbook.Name | ⑧シート名+$印 [db$] |
CSV | ③ {Microsoft Access Text Driver (*.txt, *.csv)} | ⑥パス名 ThisWorkbook.Path & "¥" | ⑨CSVファイル名 [its-041.csv] |
7ー2ー1.ConnectionでSQL文を実行しレコードセット取得
図55のNo.5のコードは、以下のようになります。- '========== ⇩(14) ConnectionでSQL文を実行しレコードセット取得 ============
- Sub Pattern05()
- Dim cn As Object '←Connectionオブジェクト
- Dim rs As Object '←Recordsetオブジェクト
- Dim SQL As String '←テーブル名、又はSQL文
- Dim s As String '←接続文字列
- Dim i As Integer '←レコードの行位置
- Set cn = CreateObject("ADODB.Connection")
' s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←①Accessドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←④Accessデータソース情報- s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" '←②Excelドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";" '←⑤Excelデータソース情報
' s = "Driver={Microsoft Access Text Driver (*.txt, *.csv)};" '←③CSVドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥;" '←⑥CSVデータソース情報- s = s & "ReadOnly=1;"
- cn.Provider = "MSDASQL"
- cn.connectionstring = s
- cn.Open
' SQL = "TestTable"'←⑦Accessテーブル- SQL = "[db$]" '←⑧Excelテーブル(シート名)
' SQL = "[its-041.csv]"'←⑨CSVテーブル(ファイル名)- SQL = "Select * from " & SQL
- Set rs = cn.Execute(SQL)
- With Sheet1.Range("B2")
- .CurrentRegion.ClearContents
- Do While Not rs.EOF
- .Offset(i, 0) = rs.Fields(0).Value
- .Offset(i, 1) = rs.Fields(1).Value
- .Offset(i, 2) = rs.Fields(2).Value
- .Offset(i, 3) = rs.Fields(3).Value
- rs.MoveNext
- i = i + 1
- Loop
- End With
- rs.Close
- cn.Close
- Set rs = Nothing
- Set cn = Nothing
- End Sub
498行目「Set cn = CreateObject("ADODB.Connection")」で、Connectionオブジェクトを生成します。
503行目「s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};"」でドライバー情報を文字列にし、504行目「s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";"」でデータソース情報(=Excelファイル名)を追加します。
なおAccessをデータベースとする時には見え消しにしてある500~501行目を使用し、CSVをデータベースとする時には506~507行目を使用します。
509行目「s = s & "ReadOnly=1;"」では、読込専用(True)の設定をしています。なお図25で説明したように、Excelの既定はReadOnly=1(True)ですので省略してもOKです。またAccessとCSVではReadOnly=0(False)が既定となります。
511行目「cn.Provider = "MSDASQL"」で、MSDASQLプロバイダーを設定します。なおADOの既定プロバイダーはMSDASQLですので、省略してもOKです。
512行目「cn.connectionstring = s」で、500~509行目で準備した接続情報文字列をConnectionオブジェクトのconnectionstringプロパティに指定します。
514行目「cn.Open」で、データベースに接続します。
517行目「SQL = "[db$]"」で、テーブル名を一旦変数SQLに代入しますが、ここではSQL文内のテーブル名とするため、「Excelのシート名+$印 を角カッコで囲む」ようにします。なおCSVファイルの場合も、518行目「SQL = "[its-041.csv]"」の様に角カッコでCSVファイル名を囲む必要があります。Accessについては、516行目「SQL = "TestTable"」のようにテーブル名のままとします。
520行目「SQL = "Select * from " & SQL」で、実行するSQL文を組み立てます。なお、「from」と「テーブル名」の間をスペースで区切る必要があるため、「from の後ろにスペースを1つ入れておく」のがポイントです。
522行目「Set rs = cn.Execute(SQL)」では、右辺でConnectionオブジェクトのExecuteメソッドにSQL文を指定して実行させます。今回のSQL文は「Select ・・・」ですのでデータとしてレコードセットが戻されます。そのレコードセットを左辺の変数rsで受け取ることで、変数rsはRecordsetオブジェクトになります。この時点ではRecordsetは開かれた状態です。
そのレコードセットの処理が524~534行目になります。Do~Loopを使いレコードセットの終端になるまで繰り返し、4列のデータをワークシートに書き込んでいます。
処理が終了したら、536行目「rs.Close」でレコードセットを閉じます。Recordset.Openメソッドは実行していませんが、522行目を実行することにより変数rs(Recordsetオブジェクト)は開いていますので、処理終了後に閉じる必要があります。最後に537行目「cn.Close」で接続を閉じます。
7ー2ー2.CommandでSQL文を実行しレコードセット取得
図55のNo.6のコードは、以下のようになります。- '========== ⇩(15) CommandでSQL文を実行しレコードセット取得 ============
- Sub Pattern06()
- Dim cn As Object '←Connectionオブジェクト
- Dim rs As Object '←Recordsetオブジェクト
- Dim cmd As Object '←Commandオブジェクト
- Dim SQL As String '←テーブル名、又はSQL文
- Dim s As String '←接続文字列
- Dim i As Integer '←レコードの行位置
- Set cn = CreateObject("ADODB.Connection")
- Set cmd = CreateObject("ADODB.Command")
' s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←①Accessドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←④Accessデータソース情報- s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" '←②Excelドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";" '←⑤Excelデータソース情報
' s = "Driver={Microsoft Access Text Driver (*.txt, *.csv)};" '←③CSVドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥;" '←⑥CSVデータソース情報- s = s & "ReadOnly=1;"
- cn.Provider = "MSDASQL"
- cn.connectionstring = s
- cn.Open
' SQL = "TestTable"'←⑦Accessテーブル- SQL = "[db$]" '←⑧Excelテーブル(シート名)
' SQL = "[its-041.csv]"'←⑨CSVテーブル(ファイル名)- SQL = "Select * from " & SQL
- cmd.ActiveConnection = cn
- cmd.CommandText = SQL
- Set rs = cmd.Execute
- With Sheet1.Range("B2")
- .CurrentRegion.ClearContents
- Do While Not rs.EOF
- .Offset(i, 0) = rs.Fields(0).Value
- .Offset(i, 1) = rs.Fields(1).Value
- .Offset(i, 2) = rs.Fields(2).Value
- .Offset(i, 3) = rs.Fields(3).Value
- rs.MoveNext
- i = i + 1
- Loop
- End With
- rs.Close
- cn.Close
- Set rs = Nothing
- Set cmd = Nothing
- Set cn = Nothing
- End Sub
559行目「Set cn = CreateObject("ADODB.Connection")」でConnectionオブジェクトを生成し、560行目「Set cmd = CreateObject("ADODB.Command")」でCommandオブジェクトを生成します。
565行目「s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};"」でドライバー情報を文字列にし、566行目「s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";"」でデータソース情報(=Excelファイル名)を追加します。
なおAccessをデータベースとする時には見え消しにしてある562~563行目を使用し、CSVをデータベースとする時には568~569行目を使用します。
571行目「s = s & "ReadOnly=1;"」では、読込専用(True)の設定をしています。なお図25で説明したように、Excelの既定はReadOnly=1(True)ですので省略してもOKです。またAccessとCSVではReadOnly=0(False)が既定となります。
573行目「cn.Provider = "MSDASQL"」で、MSDASQLプロバイダーを設定します。なおADOの既定プロバイダーはMSDASQLですので、省略してもOKです。
574行目「cn.connectionstring = s」で、562~571行目で準備した接続情報文字列をConnectionオブジェクトのconnectionstringプロパティに指定します。
576行目「cn.Open」で、データベースに接続します。
579行目「SQL = "[db$]"」で、テーブル名を一旦変数SQLに代入しますが、ここではSQL文内のテーブル名とするため、「Excelのシート名+$印 を角カッコで囲む」ようにします。なおCSVファイルの場合も、580行目「SQL = "[its-041.csv]"」の様に角カッコでCSVファイル名を囲む必要があります。Accessについては、578行目「SQL = "TestTable"」のようにテーブル名のままとします。
582行目「SQL = "Select * from " & SQL」で、実行するSQL文を組み立てます。
584行目「cmd.ActiveConnection = cn」は、接続中のConnectionオブジェクトをCommandオブジェクトのActiveConnectionに指定し、ConnectionとCommandを結び付けています。
585行目「cmd.CommandText = SQL」では、CommandオブジェクトのCommandTextにSQL文を指定しています。
587行目「Set rs = cmd.Execute」の右辺では、CommandオブジェクトのExecuteメソッドを実行し「ActiveConnectionプロパティに設定したデータベースに対し、CommandTextプロパティに設定したSQL文を実行」しています。そしてその戻り値であるレコードセットを左辺の変数rsに代入しています。
データのレコードセットが得られましたので、589~599行目で処理をしています。Do~Loopを使いレコードセットの終端になるまで繰り返し、4列のデータをワークシートに書き込みます。
処理が終了したら、601行目「rs.Close」でレコードセットを閉じ、602行目「cn.Close」で接続を閉じます。
7ー2ー3.CommandにSQL文を格納後Recordsetで取得
図55のNo.7のコードは、以下のようになります。- '========== ⇩(16) ConnectionでSQL文を実行しレコードセット取得 ============
- Sub Pattern07()
- Dim cn As Object '←Connectionオブジェクト
- Dim rs As Object '←Recordsetオブジェクト
- Dim cmd As Object '←Commandオブジェクト
- Dim SQL As String '←テーブル名、又はSQL文
- Dim s As String '←接続文字列
- Dim i As Integer '←レコードの行位置
- Set cn = CreateObject("ADODB.Connection")
- Set rs = CreateObject("ADODB.Recordset")
- Set cmd = CreateObject("ADODB.Command")
' s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←①Accessドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←④Accessデータソース情報- s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" '←②Excelドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";" '←⑤Excelデータソース情報
' s = "Driver={Microsoft Access Text Driver (*.txt, *.csv)};" '←③CSVドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥;" '←⑥CSVデータソース情報- s = s & "ReadOnly=1;"
- cn.Provider = "MSDASQL"
- cn.connectionstring = s
- cn.Open
' SQL = "TestTable"'←⑦Accessテーブル- SQL = "[db$]" '←⑧Excelテーブル(シート名)
' SQL = "[its-041.csv]"'←⑨CSVテーブル(ファイル名)- SQL = "Select * from " & SQL
- cmd.ActiveConnection = cn
- cmd.CommandText = SQL
- rs.Open cmd
- With Sheet1.Range("B2")
- .CurrentRegion.ClearContents
- Do While Not rs.EOF
- .Offset(i, 0) = rs.Fields(0).Value
- .Offset(i, 1) = rs.Fields(1).Value
- .Offset(i, 2) = rs.Fields(2).Value
- .Offset(i, 3) = rs.Fields(3).Value
- rs.MoveNext
- i = i + 1
- Loop
- End With
- rs.Close
- cn.Close
- Set rs = Nothing
- Set cmd = Nothing
- Set cn = Nothing
- End Sub
629行目「Set cn = CreateObject("ADODB.Connection")」でConnectionオブジェクトを生成し、630行目「Set rs = CreateObject("ADODB.Recordset")」でRecordsetオブジェクトを生成。また631行目「Set cmd = CreateObject
636行目「s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};"」でドライバー情報を文字列にし、637行目「s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";"」でデータソース情報(=Excelファイル名)を追加します。
なおAccessをデータベースとする時には見え消しにしてある633~634行目を使用し、CSVをデータベースとする時には639~640行目を使用します。
642行目「s = s & "ReadOnly=1;"」では、読込専用(True)の設定をしています。なお図25で説明したように、Excelの既定はReadOnly=1(True)ですので省略してもOKです。またAccessとCSVではReadOnly=0(False)が既定となります。
644行目「cn.Provider = "MSDASQL"」で、MSDASQLプロバイダーを設定します。なおADOの既定プロバイダーはMSDASQLですので、省略してもOKです。
645行目「cn.connectionstring = s」で、633~642行目で準備した接続情報文字列をConnectionオブジェクトのconnectionstringプロパティに指定します。
647行目「cn.Open」で、データベースに接続します。
650行目「SQL = "[db$]"」で、テーブル名を一旦変数SQLに代入しますが、ここではSQL文内のテーブル名とするため、「Excelのシート名+$印 を角カッコで囲む」ようにします。なおCSVファイルの場合も、651行目「SQL = "[its-041.csv]"」の様に角カッコでCSVファイル名を囲む必要があります。Accessについては、649行目「SQL = "TestTable"」のようにテーブル名のままとします。
653行目「SQL = "Select * from " & SQL」で、実行するSQL文を組み立てます。
655行目「cmd.ActiveConnection = cn」は、接続中のConnectionオブジェクトをCommandオブジェクトのActiveConnectionに指定し、ConnectionとCommandを結び付けています。
656行目「cmd.CommandText = SQL」では、CommandオブジェクトのCommandTextにSQL文を指定しています。
658行目「rs.Open cmd」では、RecordsetオブジェクトのOpenメソッドを実行しています。第1パラメータに接続情報とSQL文を格納したCommandオブジェクトを指定しています。
データのレコードセットが得られたら、660~670行目で処理をしています。Do~Loopを使いレコードセットの終端になるまで繰り返し、4列のデータをワークシートに書き込みます。
処理が終了したら、672行目「rs.Close」でレコードセットを閉じ、673行目「cn.Close」で接続を閉じます。
7ー2ー4.Recordsetに直接SQL文を指定しレコードセット取得
図55のNo.8のコードは、以下のようになります。- '========== ⇩(17) Recordsetに直接SQL文を指定しレコードセット取得 ============
- Sub Pattern08()
- Dim cn As Object '←Connectionオブジェクト
- Dim rs As Object '←Recordsetオブジェクト
- Dim SQL As String '←テーブル名、又はSQL文
- Dim s As String '←接続文字列
- Dim i As Integer '←レコードの行位置
- Set cn = CreateObject("ADODB.Connection")
- Set rs = CreateObject("ADODB.Recordset")
' s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←①Accessドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←④Accessデータソース情報- s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" '←②Excelドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";" '←⑤Excelデータソース情報
' s = "Driver={Microsoft Access Text Driver (*.txt, *.csv)};" '←③CSVドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥;" '←⑥CSVデータソース情報- s = s & "ReadOnly=1;"
- cn.Provider = "MSDASQL"
- cn.connectionstring = s
- cn.Open
' SQL = "TestTable"'←⑦Accessテーブル- SQL = "[db$]" '←⑧Excelテーブル(シート名)
' SQL = "[its-041.csv]"'←⑨CSVテーブル(ファイル名)- SQL = "Select * from " & SQL
- rs.Open SQL, cn
- With Sheet1.Range("B2")
- .CurrentRegion.ClearContents
- Do While Not rs.EOF
- .Offset(i, 0) = rs.Fields(0).Value
- .Offset(i, 1) = rs.Fields(1).Value
- .Offset(i, 2) = rs.Fields(2).Value
- .Offset(i, 3) = rs.Fields(3).Value
- rs.MoveNext
- i = i + 1
- Loop
- End With
- rs.Close
- cn.Close
- Set rs = Nothing
- Set cn = Nothing
- End Sub
698行目「Set cn = CreateObject("ADODB.Connection")」でConnectionオブジェクトを生成し、699行目「Set rs = CreateObject("ADODB.Recordset")」でRecordsetオブジェクトを生成します。
704行目「s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};"」でドライバー情報を文字列にし、705行目「s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";"」でデータソース情報(=Excelファイル名)を追加します。
なおAccessをデータベースとする時には見え消しにしてある701~702行目を使用し、CSVをデータベースとする時には707~708行目を使用します。
710行目「s = s & "ReadOnly=1;"」では、読込専用(True)の設定をしています。なお図25で説明したように、Excelの既定はReadOnly=1(True)ですので省略してもOKです。またAccessとCSVではReadOnly=0(False)が既定となります。
712行目「cn.Provider = "MSDASQL"」で、MSDASQLプロバイダーを設定します。なおADOの既定プロバイダーはMSDASQLですので、省略してもOKです。
713行目「cn.connectionstring = s」で、701~710行目で準備した接続情報文字列をConnectionオブジェクトのconnectionstringプロパティに指定します。
715行目「cn.Open」で、データベースに接続します。
718行目「SQL = "[db$]"」で、テーブル名を一旦変数SQLに代入しますが、ここではSQL文内のテーブル名とするため、「Excelのシート名+$印 を角カッコで囲む」ようにします。なおCSVファイルの場合も、719行目「SQL = "[its-041.csv]"」の様に角カッコでCSVファイル名を囲む必要があります。Accessについては、717行目「SQL = "TestTable"」のようにテーブル名のままとします。
721行目「SQL = "Select * from " & SQL」で、実行するSQL文を組み立てます。
723行目「rs.Open SQL, cn」では、RecordsetオブジェクトのOpenメソッドを実行しています。第1パラメータには721行目で作成したSQL文を、第2パラメータには接続しているConnectionオブジェクト(変数cn)を指定します。
データのレコードセットが得られたら、725~735行目で処理をしています。Do~Loopを使いレコードセットの終端になるまで繰り返し、4列のデータをワークシートに書き込みます。
処理が終了したら、737行目「rs.Close」でレコードセットを閉じ、738行目「cn.Close」で接続を閉じます。
7ー3.SQL(Insert等)文で操作
データベースに接続し、「Insertなどのデータを変更させるSQL文」を操作するコードを以下で紹介します。なお、Excelのシートデータベースについて説明しますが、以下のようにコードを切り替えることで、Access・CSVをデータベースの場合にすることが出来ます。また、SQL文をInsert・Update・Deleteで切り替える事で異なる処理が可能です。
なお丸番号は、図67・図68・図69・図70で同じにしてあります。
ドライバ(Driver=) | データベース(DBQ=) | SQL文内 のテーブル | SQL文 | |
---|---|---|---|---|
Access | ① {Microsoft Access Driver (*.mdb, *.accdb)} | ④パス名+ファイル名 ThisWorkbook.Path & "¥" & "its-041.accdb" | ⑦テーブル名 TestTable | ⑪ Insert文 ⑫ Update文 ⑬ Delete文 |
Excel | ② {Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)} | ⑤パス名+ファイル名 ThisWorkbook.Path & "¥" & ThisWorkbook.Name | ⑧シート名+$印 [db$] | ⑪ Insert文 ⑫ Update文 |
CSV | ③ {Microsoft Access Text Driver (*.txt, *.csv)} | ⑥パス名 ThisWorkbook.Path & "¥" | ⑨CSVファイル名 [its-041.csv] | ⑪ Insert文 |
7ー3ー1.ConnectionでSQL文を実行しデータ変更
図55のNo.9のコードは、以下のようになります。- '========== ⇩(18) ConnectionでSQL文を実行しデータ変更 ============
- Sub Pattern09()
- Dim cn As Object '←Connectionオブジェクト
- Dim SQL As String '←テーブル名、又はSQL文
- Dim s As String '←接続文字列
- Set cn = CreateObject("ADODB.Connection")
' s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←①Accessドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←④Accessデータソース情報- s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" '←②Excelドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";" '←⑤Excelデータソース情報
' s = "Driver={Microsoft Access Text Driver (*.txt, *.csv)};" '←③CSVドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥;" '←⑥CSVデータソース情報- s = s & "ReadOnly=0;"
- cn.Provider = "MSDASQL" '←プロバイダー設定
- cn.connectionstring = s '←ドライバー+データソース情報設定
- cn.Open
' SQL = "TestTable"'←⑦Accessテーブル- SQL = "[db$]" '←⑧Excelテーブル(シート名)
' SQL = "[its-041.csv]"'←⑨CSVテーブル(ファイル名)- SQL = "Insert into " & SQL & " (St,Nu,Dt,BL) values ('PQR',897,#11/20/2000#,True)" '←⑪Insert文
' SQL = "Update " & SQL & " set St='XYZ' where DT=#2000/11/20#"'←⑫Update文' SQL = "Delete from " & SQL & " where Dt=#11/20/2000#"'←⑬Delete文- cn.Execute SQL
- cn.Close
- Set cn = Nothing
- End Sub
756行目「Set cn = CreateObject("ADODB.Connection")」でConnectionオブジェクトを生成します。
761行目「s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};"」でドライバー情報を文字列にし、762行目「s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";"」でデータソース情報(=Excelファイル名)を追加します。
なおAccessをデータベースとする時には見え消しにしてある758~759行目を使用し、CSVをデータベースとする時には764~765行目を使用します。
767行目「s = s & "ReadOnly=0;"」では、書き込み可(False)の設定をしています。なお図25で説明したように、Excelの既定はReadOnly=1(True)ですので、省略するとエラーが発生します。またAccessとCSVではReadOnly=0(False)が既定ですので省略してもOKです。
769行目「cn.Provider = "MSDASQL"」で、MSDASQLプロバイダーを設定します。なおADOの既定プロバイダーはMSDASQLですので、省略してもOKです。
770行目「cn.connectionstring = s」で、758~767行目で準備した接続情報文字列をConnectionオブジェクトのconnectionstringプロパティに指定します。
772行目「cn.Open」で、データベースに接続します。
775行目「SQL = "[db$]"」で、テーブル名を一旦変数SQLに代入しますが、ここではSQL文内のテーブル名とするため、「Excelのシート名+$印 を角カッコで囲む」ようにします。なおCSVファイルの場合も、776行目「SQL = "[its-041.csv]"」の様に角カッコでCSVファイル名を囲む必要があります。Accessについては、774行目「SQL = "TestTable"」のようにテーブル名のままとします。
778行目「SQL = "Insert into " & SQL & " (St,Nu,Dt,BL) values ('PQR',897,#11/20/2000#,True)"」でInsert文を組み立てています。
データの書き換えの場合は779行目「"Update " & SQL & " set St='XYZ' where DT=#2000/11/20#"」を、データ削除の場合は780行目「"Delete from " & SQL & " where Dt=#11/20/2000#"」のSQL文を使用します。
なお、Excelの場合はInsert文とUpdate文、CSVの場合はInsert文のみが使用でき、その他のSQL文ではエラーとなります。
782行目「cn.Execute SQL」では、ConnectionオブジェクトのExecuteメソッドで、第1パラメータに指定したSQL文(774~780行目で作成)を実行します。
実行終了したら、784行目「cn.Close」で接続を閉じます。
7ー3ー2.CommandでSQL文を実行しデータ変更
図55のNo.10のコードは、以下のようになります。- '========== ⇩(19) CommandでSQL文を実行しデータ変更 ============
- Sub Pattern10()
- Dim cn As Object '←Connectionオブジェクト
- Dim cmd As Object '←Commandオブジェクト
- Dim SQL As String '←テーブル名、又はSQL文
- Dim s As String '←接続文字列
- Set cn = CreateObject("ADODB.Connection")
- Set cmd = CreateObject("ADODB.Command")
' s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←①Accessドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←④Accessデータソース情報- s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" '←②Excelドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";" '←⑤Excelデータソース情報
' s = "Driver={Microsoft Access Text Driver (*.txt, *.csv)};" '←③CSVドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥;" '←⑥CSVデータソース情報- s = s & "ReadOnly=0;"
- cn.Provider = "MSDASQL" '←プロバイダー設定
- cn.connectionstring = s '←ドライバー+データソース情報設定
- cn.Open
' SQL = "TestTable"'←⑦Accessテーブル- SQL = "[db$]" '←⑧Excelテーブル(シート名)
' SQL = "[its-041.csv]"'←⑨CSVテーブル(ファイル名)- SQL = "Insert into " & SQL & " (St,Nu,Dt,BL) values ('PQR',897,#11/20/2000#,True)" '←⑪Insert文
' SQL = "Update " & SQL & " set St='XYZ' where DT=#2000/11/20#"'←⑫Update文' SQL = "Delete from " & SQL & " where Dt=#11/20/2000#"'←⑬Delete文- cmd.ActiveConnection = cn
- cmd.CommandText = SQL
- cmd.Execute
- cn.Close
- Set cmd = Nothing
- Set cn = Nothing
- End Sub
807行目「Set cn = CreateObject("ADODB.Connection")」でConnectionオブジェクトを生成し、808行目「Set cmd = CreateObject("ADODB.Command")」でCommandオブジェクトを生成します。
813行目「s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};"」でドライバー情報を文字列にし、814行目「s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";"」でデータソース情報(=Excelファイル名)を追加します。
なおAccessをデータベースとする時には見え消しにしてある810~811行目を使用し、CSVをデータベースとする時には816~817行目を使用します。
819行目「s = s & "ReadOnly=0;"」では、書き込み可(False)の設定をしています。なお図25で説明したように、Excelの既定はReadOnly=1(True)ですので、省略するとエラーが発生します。またAccessとCSVではReadOnly=0(False)が既定ですので省略してもOKです。
821行目「cn.Provider = "MSDASQL"」で、MSDASQLプロバイダーを設定します。なおADOの既定プロバイダーはMSDASQLですので、省略してもOKです。
822行目「cn.connectionstring = s」で、810~819行目で準備した接続情報文字列をConnectionオブジェクトのconnectionstringプロパティに指定します。
824行目「cn.Open」で、データベースに接続します。
827行目「SQL = "[db$]"」で、テーブル名を一旦変数SQLに代入しますが、ここではSQL文内のテーブル名とするため、「Excelのシート名+$印 を角カッコで囲む」ようにします。なおCSVファイルの場合も、828行目「SQL = "[its-041.csv]"」の様に角カッコでCSVファイル名を囲む必要があります。Accessについては、826行目「SQL = "TestTable"」のようにテーブル名のままとします。
830行目「SQL = "Insert into " & SQL & " (St,Nu,Dt,BL) values ('PQR',897,#11/20/2000#,True)"」でInsert文を組み立てています。
データの書き換えの場合は831行目「"Update " & SQL & " set St='XYZ' where DT=#2000/11/20#"」を、データ削除の場合は832行目「"Delete from " & SQL & " where Dt=#11/20/2000#"」のSQL文を使用します。
なお、Excelの場合はInsert文とUpdate文、CSVの場合はInsert文のみが使用でき、その他のSQL文ではエラーとなります。
834行目「cmd.ActiveConnection = cn」は、接続中のConnectionオブジェクトをCommandオブジェクトのActiveConnectionに指定し、ConnectionとCommandを結び付けています。
835行目「cmd.CommandText = SQL」では、CommandオブジェクトのCommandTextにSQL文を指定しています。
837行目「cmd.Execute」で、CommandオブジェクトのExecuteメソッドを実行し「ActiveConnectionプロパティに設定したデータベースに対し、CommandTextプロパティに設定したSQL文を実行」しています。
実行終了したら、839行目「cn.Close」で接続を閉じます。
7ー3ー3.CommandにSQL文を格納後Recordsetで実行しデータ変更
図55のNo.11のコードは、以下のようになります。- '========== ⇩(20) CommandにSQL文を格納後Recordsetで実行しデータ変更 ============
- Sub Pattern11()
- Dim cn As Object '←Connectionオブジェクト
- Dim rs As Object '←Recordsetオブジェクト
- Dim cmd As Object '←Commandオブジェクト
- Dim SQL As String '←テーブル名、又はSQL文
- Dim s As String '←接続文字列
- Set cn = CreateObject("ADODB.Connection")
- Set rs = CreateObject("ADODB.Recordset")
- Set cmd = CreateObject("ADODB.Command")
' s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←①Accessドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←④Accessデータソース情報- s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" '←②Excelドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";" '←⑤Excelデータソース情報
' s = "Driver={Microsoft Access Text Driver (*.txt, *.csv)};" '←③CSVドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥;" '←⑥CSVデータソース情報- s = s & "ReadOnly=0;"
- cn.Provider = "MSDASQL" '←プロバイダー設定
- cn.connectionstring = s '←ドライバー+データソース情報設定
- cn.Open
' SQL = "TestTable"'←⑦Accessテーブル- SQL = "[db$]" '←⑧Excelテーブル(シート名)
' SQL = "[its-041.csv]"'←⑨CSVテーブル(ファイル名)- SQL = "Insert into " & SQL & " (St,Nu,Dt,BL) values ('PQR',897,#11/20/2000#,True)" '←⑪Insert文
' SQL = "Update " & SQL & " set St='XYZ' where DT=#2000/11/20#"'←⑫Update文' SQL = "Delete from " & SQL & " where Dt=#11/20/2000#"'←⑬Delete文- cmd.ActiveConnection = cn
- cmd.CommandText = SQL
- rs.Open cmd
- cn.Close
- Set rs = Nothing
- Set cmd = Nothing
- Set cn = Nothing
- End Sub
858行目「Set cn = CreateObject("ADODB.Connection")」でConnectionオブジェクトを生成し、859行目「Set rs = CreateObject("ADODB.Recordset")」でRecordsetオブジェクトを生成。860行目「Set cmd = CreateObject
865行目「s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};"」でドライバー情報を文字列にし、866行目「s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";"」でデータソース情報(=Excelファイル名)を追加します。
なおAccessをデータベースとする時には見え消しにしてある862~863行目を使用し、CSVをデータベースとする時には868~869行目を使用します。
871行目「s = s & "ReadOnly=0;"」では、書き込み可(False)の設定をしています。なお図25で説明したように、Excelの既定はReadOnly=1(True)ですので、省略するとエラーが発生します。またAccessとCSVではReadOnly=0(False)が既定ですので省略してもOKです。
873行目「cn.Provider = "MSDASQL"」で、MSDASQLプロバイダーを設定します。なおADOの既定プロバイダーはMSDASQLですので、省略してもOKです。
874行目「cn.connectionstring = s」で、862~871行目で準備した接続情報文字列をConnectionオブジェクトのconnectionstringプロパティに指定します。
876行目「cn.Open」で、データベースに接続します。
879行目「SQL = "[db$]"」で、テーブル名を一旦変数SQLに代入しますが、ここではSQL文内のテーブル名とするため、「Excelのシート名+$印 を角カッコで囲む」ようにします。なおCSVファイルの場合も、880行目「SQL = "[its-041.csv]"」の様に角カッコでCSVファイル名を囲む必要があります。Accessについては、878行目「SQL = "TestTable"」のようにテーブル名のままとします。
882行目「SQL = "Insert into " & SQL & " (St,Nu,Dt,BL) values ('PQR',897,#11/20/2000#,True)"」でInsert文を組み立てています。
データの書き換えの場合は883行目「"Update " & SQL & " set St='XYZ' where DT=#2000/11/20#"」を、データ削除の場合は884行目「"Delete from " & SQL & " where Dt=#11/20/2000#"」のSQL文を使用します。
なお、Excelの場合はInsert文とUpdate文、CSVの場合はInsert文のみが使用でき、その他のSQL文ではエラーとなります。
886行目「cmd.ActiveConnection = cn」は、接続中のConnectionオブジェクトをCommandオブジェクトのActiveConnectionに指定し、ConnectionとCommandを結び付けています。
887行目「cmd.CommandText = SQL」では、CommandオブジェクトのCommandTextにSQL文を指定しています。
889行目「rs.Open cmd」では、RecordsetオブジェクトのOpenメソッドの第1パラメータにCommandオブジェクトを指定して実行しています。この時、第2パラメータは省略します。
この889行目は「ActiveConnectionプロパティに設定したデータベースに対し、CommandTextプロパティに設定したSQL文を実行」している事になります。
実行が完了したら、891行目「cn.Close」でデータベース接続を閉じます。
なお、データ変更用のSQL文(Insert、Update、Delete)を889行目のRecordset.Openで実行した時は「Recordset.Closeは実行しない」ことに注意ください。このデータ変更SQLを実行した直後には、RecordsetオブジェクトのStateプロパティがゼロ(=レコードセットは閉じられている)となり、更に「Recordset.Close を実行してしまうと、エラーが発生」します。
7ー3ー4.SQL文を直接ecordsetで実行しデータ変更
図55のNo.12のコードは、以下のようになります。- '========== ⇩(21) SQL文を直接ecordsetで実行しデータ変更 ============
- Sub Pattern12()
- Dim cn As Object '←Connectionオブジェクト
- Dim rs As Object '←Recordsetオブジェクト
- Dim SQL As String '←テーブル名、又はSQL文
- Dim s As String '←接続文字列
- Set cn = CreateObject("ADODB.Connection")
- Set rs = CreateObject("ADODB.Recordset")
' s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←①Accessドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←④Accessデータソース情報- s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" '←②Excelドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";" '←⑤Excelデータソース情報
' s = "Driver={Microsoft Access Text Driver (*.txt, *.csv)};" '←③CSVドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥;" '←⑥CSVデータソース情報- s = s & "ReadOnly=0;"
- cn.Provider = "MSDASQL" '←プロバイダー設定
- cn.connectionstring = s '←ドライバー+データソース情報設定
- cn.Open
' SQL = "TestTable"'←⑦Accessテーブル- SQL = "[db$]" '←⑧Excelテーブル(シート名)
' SQL = "[its-041.csv]"'←⑨CSVテーブル(ファイル名)- SQL = "Insert into " & SQL & " (St,Nu,Dt,BL) values ('PQR',897,#11/20/2000#,True)" '←⑪Insert文
' SQL = "Update " & SQL & " set St='XYZ' where DT=#2000/11/20#"'←⑫Update文' SQL = "Delete from " & SQL & " where Dt=#11/20/2000#"'←⑬Delete文- rs.Open SQL, cn
- cn.Close
- Set rs = Nothing
- Set cn = Nothing
- End Sub
907行目「Set cn = CreateObject("ADODB.Connection")」でConnectionオブジェクトを生成し、908行目「Set rs = CreateObject("ADODB.Recordset")」でRecordsetオブジェクトを生成します。
913行目「s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};"」でドライバー情報を文字列にし、914行目「s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";"」でデータソース情報(=Excelファイル名)を追加します。
なおAccessをデータベースとする時には見え消しにしてある910~911行目を使用し、CSVをデータベースとする時には916~917行目を使用します。
919行目「s = s & "ReadOnly=0;"」では、書き込み可(False)の設定をしています。なお図25で説明したように、Excelの既定はReadOnly=1(True)ですので、省略するとエラーが発生します。またAccessとCSVではReadOnly=0(False)が既定ですので省略してもOKです。
921行目「cn.Provider = "MSDASQL"」で、MSDASQLプロバイダーを設定します。なおADOの既定プロバイダーはMSDASQLですので、省略してもOKです。
922行目「cn.connectionstring = s」で、910~919行目で準備した接続情報文字列をConnectionオブジェクトのconnectionstringプロパティに指定します。
924行目「cn.Open」で、データベースに接続します。
927行目「SQL = "[db$]"」で、テーブル名を一旦変数SQLに代入しますが、ここではSQL文内のテーブル名とするため、「Excelのシート名+$印 を角カッコで囲む」ようにします。なおCSVファイルの場合も、928行目「SQL = "[its-041.csv]"」の様に角カッコでCSVファイル名を囲む必要があります。Accessについては、926行目「SQL = "TestTable"」のようにテーブル名のままとします。
930行目「SQL = "Insert into " & SQL & " (St,Nu,Dt,BL) values ('PQR',897,#11/20/2000#,True)"」でInsert文を組み立てています。
データの書き換えの場合は931行目「"Update " & SQL & " set St='XYZ' where DT=#2000/11/20#"」を、データ削除の場合は932行目「"Delete from " & SQL & " where Dt=#11/20/2000#"」のSQL文を使用します。
なお、Excelの場合はInsert文とUpdate文、CSVの場合はInsert文のみが使用でき、その他のSQL文ではエラーとなります。
934行目「rs.Open SQL, cn」で、RecordsetオブジェクトのOpenメソッドの第1パラメータにSQL文を指定し、第2パラメータに接続中のConnectionオブジェクト(変数cn)を指定することで、データベースに対してデータ変更処理を行います。
実行が完了したら、936行目「cn.Close」でデータベース接続を閉じます。
なお、データ変更用のSQL文(Insert、Update、Delete)を934行目のRecordset.Openで実行した時は「Recordset.Closeは実行しない」ことに注意ください。このデータ変更SQLを実行した直後には、RecordsetオブジェクトのStateプロパティがゼロ(=レコードセットは閉じられている)となり、更に「Recordset.Close を実行してしまうと、エラーが発生」します。
8.データの一括処理
上記で紹介した「レコードセットを取得し、ワークシートにデータを書き出す」コードは、レコードセットをDo~Loopで「1レコード単位」で取り出して処理する手法でした。それとは異なる方法で「全データを一括で取り出す」事も可能です。一括で取り出すには、RecordsetオブジェクトのGetRowsメソッドを使用します。構文としては以下になります。
配列 = Recordset.GetRows( Rows, Start, Fields)
戻り値は「インデックスがゼロ始まりの二次元配列」です。指定できるパラメータは以下の3つで、全て省略可です。
パラメータ | 内容 | |
---|---|---|
Rows | 省略可 | 取り出す行数 既定=現カーソル位置 or Start指定位置から最終行まで |
Start | 省略可 | 取り出し開始のブックマーク(図72) 既定=現カーソル位置 |
Fields | 省略可 | 取り出し列番号、又は列名 既定=全列 |
第1パラメータのRowsは、GetRowsで取り出す行数を指定します。Recordset.Open直後のカーソル位置は先頭行にありますので、「省略すれば全行」が取り出せることになります。
なお取り出し行を「1」行に指定し、取り出した2次元配列をTranspose関数等で行列逆転させると「1次元配列」のデータとなります。例えば図73の988行目のような「2次元配列を前提とした処理」ではエラーが発生してしまうので注意が必要です。
第2パラメータのStartは、ブックマーク文字列、又は図72の値を指定します。省略(=adBookmarkCurrent(値=0))すると、現在のカーソル位置となります。
定数 | 値 | 内容 |
---|---|---|
adBookmarkCurrent | 0 | 現レコードから開始 |
adBookmarkFirst | 1 | 最初のレコードから開始 |
adBookmarkLast | 2 | 最後のレコードから開始 |
Microsoftや他サイトでも図72のような説明が載っているのですが、しかしMSDASQLプロバイダーで試してみると、既定のゼロ以外ではエラー(エラー内容:Recordsetはブックマークをサポートしていない)が発生してしまいます(ACE・Jetプロバイダーでも同じでした)。Recordset.Openメソッドを使い、第3パラメータ(CursorType)を調整してみたのですが同じエラーが出ます。
また、レコードセットへのブックマーク方法までは今回調べ切れず、ブックマーク文字列については今回省略しますが、上記のようなエラー内容から考えると、第2パラメータは「MSDASQL、ACE・Jetプロバイダーでは使えない」のかもしれません。
第3パラメータのFieldsは、列番号(先頭列=ゼロ)または列名(文字列)で指定します。省略すると、全列を出力します。
なお、複数列に限って出力したい場合は「Array(2,3)」のように配列の形で指定することで可能です。この例の場合は3列目+4列目を出力せよ という意味になります。
GetRowsメソッドから戻ってくるデータは「行列が逆転した配列」になります。もちろんTransposeメソッドで行列を回転させる事は可能ですが、要素内に「Nullが入っているとエラー」が発生するので注意が必要です。また1行しか取得できなかった場合にTransposeで回転させると、二次元配列が一次元配列に変わってしまうので工夫が必要です。
図62のコード(1行ずつ出力処理)をGetRowsで一括処理するのが、以下のコードになります。
- '========== ⇩(22) GetRowsでまとめてデータ取得 ============
- Sub Pattern13()
- Dim cn As Object '←Connectionオブジェクト
- Dim rs As Object '←Recordsetオブジェクト
- Dim SQL As String '←テーブル名、又はSQL文
- Dim GR As Variant '←データ配列
- Dim s As String '←接続文字列
- Set cn = CreateObject("ADODB.Connection")
' s = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};" '←①Accessドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥" & "its-041.accdb;" '←④Accessデータソース情報- s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" '←②Excelドライバー情報
- s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";" '←⑤Excelデータソース情報
' s = "Driver={Microsoft Access Text Driver (*.txt, *.csv)};" '←③CSVドライバー情報' s = s & "DBQ=" & ThisWorkbook.Path & "¥;" '←⑥CSVデータソース情報- s = s & "ReadOnly=1;"
- cn.Provider = "MSDASQL" '←プロバイダー設定
- cn.connectionstring = s '←ドライバー+データソース情報設定
- cn.Open
' SQL = "TestTable"'←⑦Accessテーブル- SQL = "[db$]" '←⑧Excelテーブル(シート名)
' SQL = "[its-041.csv]"'←⑨CSVテーブル(ファイル名)- SQL = "Select * from " & SQL
- Set rs = cn.Execute(SQL)
- With Sheet1.Range("B2")
- .CurrentRegion.ClearContents
- GR = rs.GetRows
- GR = WorksheetFunction.Transpose(GR)
- .Resize(UBound(GR, 1), UBound(GR, 2)) = GR
- End With
- rs.Close
- cn.Close
- Set rs = Nothing
- Set cn = Nothing
- End Sub
958行目「Set cn = CreateObject("ADODB.Connection")」で、Connectionオブジェクトを生成します。
963行目「s = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};"」でドライバー情報を文字列にし、964行目「s = s & "DBQ=" & ThisWorkbook.Path & "¥" & ThisWorkbook.Name & ";"」でデータソース情報(=Excelファイル名)を追加します。
なおAccessをデータベースとする時には見え消しにしてある960~961行目を使用し、CSVをデータベースとする時には966~967行目を使用します。
969行目「s = s & "ReadOnly=1;"」では、読込専用(True)の設定をしています。なお図25で説明したように、Excelの既定はReadOnly=1(True)ですので省略してもOKです。またAccessとCSVではReadOnly=0(False)が既定となります。
971行目「cn.Provider = "MSDASQL"」で、MSDASQLプロバイダーを設定します。なおADOの既定プロバイダーはMSDASQLですので、省略してもOKです。
972行目「cn.connectionstring = s」で、960~969行目で準備した接続情報文字列をConnectionオブジェクトのconnectionstringプロパティに指定します。
974行目「cn.Open」で、データベースに接続します。
977行目「SQL = "[db$]"」で、テーブル名を一旦変数SQLに代入しますが、ここではSQL文内のテーブル名とするため、「Excelのシート名+$印 を角カッコで囲む」ようにします。なおCSVファイルの場合も、978行目「SQL = "[its-041.csv]"」の様に角カッコでCSVファイル名を囲む必要があります。Accessについては、976行目「SQL = "TestTable"」のようにテーブル名のままとします。
980行目「SQL = "Select * from " & SQL」で、実行するSQL文を組み立てます。
982行目「Set rs = cn.Execute(SQL)」では、右辺でConnectionオブジェクトのExecuteメソッドにSQL文を指定して実行させます。今回のSQL文は「Select ・・・」ですのでデータとしてレコードセットが戻されます。そのレコードセットを左辺の変数rsで受け取ることで、変数rsはRecordsetオブジェクトになります。なお、この段階では、レコードセットのカーソル(操作できる行位置)は、先頭行にあります。
984~989行目では、取得したレコードセットの全データをワークシート上に1回で書き出しています。
984行目「With Sheet1.Range("B2")」では、シートへのデータ書き出しの基準点を決めています。
985行目「.CurrentRegion.ClearContents」は、その基準点を含むエリアに書かれていたデータをクリアします。
986行目「GR = rs.GetRows」では、レコードセットの全データを取得しています。この時のGetRowsメソッドにはパラメータを指定していないので、「今カーソルがある先頭行(第2パラメータ)」から「全行数(第1パラメータ)」を「全列数(第3パラメータ)」分だけ取り出す、という条件になります。取り出したデータの配列GRは、行列逆転した状態で、且つ配列インデックスはゼロ始まりです。
987行目「GR = WorksheetFunction.Transpose(GR)」では、Transpose関数で行列を逆にし、いわゆる正しい行列方向にデータ変換しています。また配列インデックスも1始まりに変換されます(取得したデータ行が1行分の場合は、Transposeにより二次元配列→一次元配列 になります)。
988行目「.Resize(UBound(GR, 1), UBound(GR, 2)) = GR」では、貼り付けサイズを配列と同じサイズにしてから、配列データを貼り付けています。(1行しか取得できなかった場合は、ここでエラー(UBound(GR, 2)が無い)が出ます)
991行目「rs.Close」でレコードセットを閉じ、992行目「cn.Close」で接続を閉じます。
なお他のパターンでも、同様にGetRowsを使い一括処理を行うことが可能です。
アプリ実例・関連する項目
「CSVファイルの読み込み」「Excelシート上にDBを作り、SQLを使ってデータを入出力する」
「オブジェクトの生成のやり方について」
「ExcelシートDBとSQLを使った会議室予約システム」
「ExcelシートDBとSQLを使った倉庫管理システム」
「複数の備品を同時予約可能な貸出台帳」
「共有資料の登録と閲覧ができるサーバーシステム」
サンプルファイル
ADOでAccess・Excel・CSVへ接続・操作(MSDASQLプロバイダー編)(its-043.xlsm)Accessデータファイル(its-041.accdb)
CSVデータファイル(its-041.csv)
セキュリティ向上を目的として「インターネット経由でダウンロードしたOfficeファイル(Excel等)のマクロは、既定でブロック」されるようにOfficeアプリケーションの既定動作が変更になりました。(2022年4月より切替開始) 解除の方法については「ダウンロードファイルのブロック解除方法」を参照下さい。 |