VBAからMySQLに接続してデータベース操作する方法のまとめ

# はじめに

VBAからMySQLに接続する方法と各種の基本操作について、備忘のためにまとめておきます。

**＜目次＞**
**[1. 基本的なコードの記載](#1-基本的なコードの記載)**
**[2. 接続方法の詳細](#2-接続方法の詳細)**
　[2-1. Driver（ドライバ）の指定](#2-1-driverドライバの指定)
　[2-2. Server（サーバ名）の指定](#2-2-serverサーバ名の指定)
　[2-3. Port（ポート番号）の指定](#2-3-portポート番号の指定)
　[2-4. Database（データベース名）の指定](#2-4-databaseデータベース名の指定)
　[2-5. ユーザー名とパスワードの指定](#2-5-ユーザー名とパスワードの指定)
　[2-6. Charset（文字セット）の指定](#2-6-charset文字セットの指定)
**[3. 主なSQL構文によるソースコード例](#3-主なsql構文によるソースコード例)**
　[3-1. SELECT文（レコードの取得）](#3-1-select文レコードの取得)
　[3-2. CREATE TABLE文（テーブルの作成）](#3-2-create-table文テーブルの作成)
　[3-3. INSERT文（レコードの追加）](#3-3-insert文レコードの追加)
　[3-4. UPDATE文（レコードの更新）](#3-4-update文レコードの更新)
　[3-5. DELETE文（レコードの削除）](#3-5-delete文レコードの削除)
　[3-6. DROP TABLE文（テーブルの削除）](#3-6-drop-table文テーブルの削除)
　[3-7. テーブルが存在するか否かを確認する](#3-7-テーブルが存在するか否かを確認する)

# 1. 基本的なコードの記載

前提として、MySQLに作成した「test_db」というデータベース（ローカルホストに作成）に、次のような「商品リスト」というテーブルを作成している状態から始めます。
（MySQLの操作に慣れない方は、[MySQLの使い方](https://www.dbonline.jp/mysql/)というサイトがお勧めです。）

```:コマンドプロンプト（MySQLのテーブル）
mysql> select * from 商品リスト;
+--------+--------+------+
| 商品ID | 商品名 | 単価 |
+--------+--------+------+
|      1 | ビール | 5000 |
|      2 | 焼き鳥 | 7000 |
|      3 | 柿ピー |  500 |
|      4 | ポテチ | 3000 |
+--------+--------+------+
4 rows in set (0.00 sec)
```

```:コマンドプロンプト（MySQLのテーブル作成時の定義）
mysql> create table 商品リスト (商品ID int primary key, 商品名 varchar(20), 単価 decimal(10));
```
上記のテーブルの内容を、VBAからSELECT文で取得するには次のようなコードを記述します。
なお、事前に[参照設定](https://qiita.com/t-yama-3/items/e79056079ffdcdb79391#1-1-2-%E5%8F%82%E7%85%A7%E8%A8%AD%E5%AE%9A%E3%82%92%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88)（`Microsoft ActiveX Data Object 6.1 Library`）をしています。
ユーザー名とパスワードは、ご自身の設定内容に修正してください。

```vb:VBAからSELECT文を実行（最低限の記載内容）
'SELECT文の実行
Sub ConnectToMysqlDatabase_Select()
    'ADOを使用してMySQLに接続
    Dim cn As New ADODB.Connection
    cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};" & _
                          "Server=localhost;" & _
                          "Database=test_db;" & _
                          "User=root;" & _
                          "Password=XXXXXXXX"
    cn.Open
    
    'SELECT文の実行（取得した内容の確認）
    Dim rs As New ADODB.Recordset
    rs.Open "SELECT * FROM 商品リスト", cn 'SQL文の実行
    Do Until rs.EOF
        Debug.Print rs("商品ID") & ", " & rs("商品名") & ", " & rs("単価")
        rs.MoveNext
    Loop

    'メモリの解放（無くとも構わない）
    rs.Close: Set rs = Nothing
    cn.Close: Set cn = Nothing
End Sub
```

```:イミディエイトウィンドウ
1, ビール, 5000
2, 焼き鳥, 7000
3, 柿ピー, 500
4, ポテチ, 3000
```

**参考サイト（MySQLにADOで接続）**
・[ADO(ActiveX Data Objects)の使い方の要点](https://excel-ubara.com/excelvba4/EXCEL273.html#sec04)
・[データベース（MySQL）に接続する（ADO）](https://excelwork.info/excel/databasemysql/)
・[C#からMySQLに接続する](https://dianxnao.com/c%E3%81%8B%E3%82%89mysql%E3%81%AB%E6%8E%A5%E7%B6%9A%E3%81%99%E3%82%8B/)

# 2. 接続方法の詳細

ここでは、**ConnectionStringプロパティ**についての説明を書いておきます。
ADOに関する基本的なことは、必要に応じて[こちらの記事](https://qiita.com/t-yama-3/items/e79056079ffdcdb79391)などを参照してください。

```vb:ConnectionStringプロパティの設定例
    cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};" & _
                          "Server=localhost;" & _
                          "Port=3306;" & _
                          "Database=test_db;" & _
                          "User=root;" & _
                          "Password=XXXXXXXX;" & _
                          "Charset=sjis;"
```

**＜ConnectionStringプロパティの設定内容一覧＞**

|キーワード|設定内容|指定例|
|---|---|---|
|Driver|ODBCドライバを指定|Driver={MySQL ODBC 8.0 Unicode Driver}|
|Server|ホスト名又はIPアドレスを指定|Server=192.168.3.5|
|Port|サーバのポート番号を指定|Port=3306|
|Database|データベース名を指定|Database=販売管理DB|
|User (UID)|ユーザー名を指定|UID=taka|
|Password (PWD)|パスワードを指定|PWD=12345678|
|Charset|クライアント側の文字コードを指定|Charset=cp932|

・キーワードと値は等号`=`で結びつけます。キーワードと値のペアごとにセミコロン`;`で区切ります。
・キーワードは、大文字と小文字は区別されません。
・`User`は`UID`、`Password`は`PWD`と書いても同じ結果となります。

**参考サイト**
・[SqlConnection.ConnectionStringプロパティ](https://docs.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlconnection.connectionstring?view=sqlclient-dotnet-core-2.1)

## 2-1. Driver（ドライバ）の指定

まず、**Driver**の指定についてです。
使用するドライバ名を波括弧で括って記述します。

```
Driver={MySQL ODBC 8.0 Unicode Driver}
```

このドライバ名は、PCにインストールされている[ODBC](https://ja.wikipedia.org/wiki/Open_Database_Connectivity)ドライバのバージョンに基づいて記述することが必要です。
ドライバは、**[ODBCデータソースアドミニストレーター](https://docs.microsoft.com/ja-jp/sql/database-engine/configure-windows/open-the-odbc-data-source-administrator?view=sql-server-ver15)**から確認できます。以下、確認方法について書いておきます。

### 2-1-1. ODBCデータソースアドミニストレーターの起動方法

ODBCデータソースアドミニストレーターは次のような画面で表示されます。
![2021-02-21 225805.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/5d9e6450-0fdc-f8b2-b577-de0e29e99d43.png)
ODBCデータソースアドミニストレーターの起動方法には、次のような起動方法があります。

**①スタートメニューから起動**
Windows10では、スタートメニューから「ODBC データ ソース」と検索して起動することができます。

**②コントロールパネルから起動**
コントロールパネルからでも、「システムとセキュリティ」→「管理ツール」をクリックすれば、管理ツールのショートカット一覧が表示されますので、そこから使用する環境に合わせて`ODBC データ ソース (64 ビット)`又は`ODBC Data Sources (32-bit)`のどちらかを起動します。

**③実行ファイルから直接起動**
次のディレクトリにあるファイルから直接起動することもできます。

```
＜64ビット版＞
C:\Windows\System32\odbcad32.exe

＜32ビット版＞
C:\Windows\SysWOW64\odbcad32.exe
```

### 2-1-2. MySQLのODBCドライバーの確認

ODBCデータソースアドミニストレーターが起動できたら「ドライバ」タブを開きます。
すると、次のような一覧が表示されます。
![2021-02-11 164523.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/af0656df-e91c-947a-052f-a7fcf926d77a.png)
既にドライバがインストールされていれば、次の2つのドライバを確認することができると思います。

|ドライバ名|対応する文字コード|
|---|---|
|MySQL ODBC 8.0 ANSI Driver|UTF-8|
|MySQL ODBC 8.0 Unicode Driver|UTF-16(UCS-2)|

対応する文字コードは、実際に入力して確認した結果（経験則）なので、もう少し正しい表現があるかもしれません。

#### 2-1-2-1. MySQL ODBC 8.0 Unicode Driver (UTF-16の場合)

Windows VBAで使用されている文字コードはUnicode（UTF-16）なので、**MySQL ODBC 8.0 Unicode Driver**を選びます（ただし、[VBAで入力できる文字コードはSHIFT_JIS](https://www.tipsfound.com/vba/04012)なので、ここはややこしいところ）。
何にしても、WindowsのVBAであれば迷わず**MySQL ODBC 8.0 Unicode Driver**を選んでください。

#### 2-1-2-2. MySQL ODBC 8.0 ANSI Driver (UTF-8の場合)

一方、**MySQL ODBC 8.0 ANSI Driver**を使用するとデータベース名、テーブル名、カラム名がUTF-8で読み込まれるため、VBAでは文字化けして使用は困難となります。
例えば、「商品ID」と「商品名」というカラムがあると、UTF-8で取得された文字列を無理矢理SHIFT_JISで読もうとするので、次のような文字化けが起こります。

|MySQLのカラム名|UTF-8文字コード|ANSI Driverを介した表示（SHIFT_JISの文字コード）|
|---|---|---|
|商品ID|e5 95 86 e5 93 81 49 44|蝠・刀ID（e5 95 / 〓 / 93 81 / 49 / 44）|
|商品名|e5 95 86 e5 93 81 e5 90 8d|蝠・刀蜷・（e5 95 / 〓 / 93 81 / e5 90 / 〓）|

ただし、各レコードのデータ（データベースに格納する個々のデータ）は、**ANSI Driver**でも文字化けせずに読み込むことができます（各レコードのデータは、必要に応じて**Charset**の設定で文字コードを指定することもできます）。
なので、データベース名、テーブル名、カラム名を全て英数字（正確にはASCII文字）にするなどの処置を行えば、**ANSI Driver**でも何とかなります（やる価値はないと思いますが）。

なお、Macの文字コードはUTF-8なので、MacでODBCドライバを使用する場合は、こちらのANSI Driverを使うのかもしれません（試していないのでわかりません）。

**参考サイト**
・[ODBCドライバーのバージョンを確認する](https://lilia-study.com/pc/soft/odbc/version.html)
・[10.1.10 Unicode のサポート](https://dev.mysql.com/doc/refman/5.6/ja/charset-unicode.html)

### 2-1-3. MySQLのODBCドライバーが無い場合

私の手元の環境では、MySQLのインストール時にドライバも一緒にインストールされていました（おそらく）。
使用する環境にドライバがインストールされていない場合には、次のようなWEBサイトなどを参考にして、インストールを行ってください。

**参考サイト**
・[MySQL の ODBC ドライバーをインストールする](https://www.projectgroup.info/documents/MySQL/mysql_000008.html)
・[MySQL ODBC ドライバのインストール（Windows 上）](https://www.kkaneko.jp/tools/mysql/mysqlodbcvc.html)
・[MySQLへのODBC接続設定をする](https://mgate.info/db/mysql/852/)

## 2-2. Server（サーバ名）の指定

次に、Server（サーバ名）の指定についてです。
ここは、MySQLのデータベースを格納しているホスト名又はIPアドレスを指定します。

```
＜自分のローカルPC上のMySQLデータベースを参照する場合＞
Server=localhost

＜IPアドレスで指定する場合＞
Server=192.168.3.5
```

ローカルに作成しているMySQLのデータベースは**localhost**と指定すれば大丈夫です。

### 2-2-1. ホスト名で指定する場合

Serverをホスト名で指定する方法は、色々な場合では試していないので、確認した範囲で書いておきます。
ローカルPC上のMySQLデータベースのホスト名を確認すると、次のように[自分のPC名](https://support.microsoft.com/ja-jp/office/%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E3%83%BC%E5%90%8D%E3%82%92%E7%9F%A5%E3%82%8A%E3%81%9F%E3%81%84%E5%A0%B4%E5%90%88-00384381-8aa9-4398-b81b-475f09fed618)が表示されます（参照：[mysqlで接続しているDBサーバのホスト名を確認する方法](https://qiita.com/nii_yan/items/0265f69370bbdb883655)）。

```
mysql> show variables like 'hostname';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| hostname      | DESKTOP-PC      |
+---------------+-----------------+
1 row in set, 1 warning (0.02 sec)
```

このホスト名「DESKTOP-PC」をServerに指定して接続をしてみます。

```
cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};Server=DESKTOP-PC;Database=test_db;UID=root;PWD=XXXXXXXX;"
```

しかし、次のようにアクセスが拒否されます。
![2021-02-23 120818.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/4f94f8ed-05ea-991c-3ded-0e0f0762c03e.png)
これを無理矢理接続するために、次のようなユーザーを作成します（ユーザー作成方法の詳細は「[MySQLの使い方 ユーザーの作成](https://www.dbonline.jp/mysql/user/)」を参照してください）。

```
mysql> create user 'yama'@'DESKTOP-PC' identified by '123456';
Query OK, 0 rows affected (0.53 sec)

mysql> grant select on test_db.* to 'yama'@'DESKTOP-PC';
Query OK, 0 rows affected (0.17 sec)
```
最初のCREATE USER文で、ユーザー名を「yama」、クライアントのホスト名を「DESKTOP-PC」（ローカルホスト名）、パスワードを「123456」とするユーザーを作成しています。
続くGRANT文で、作成したユーザーに、「test_db」データベースの全てのテーブルに対して、**SELECT権限**を与えています。
これにより、MySQLのサーバは、「yama@DESKTOP-PC」というユーザーに対してアクセス権を与えたことになります。

この作成したユーザーで、接続をすると無事にホスト名でAccessをすることができます。

```vb:Serverにホスト名を指定する
cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};Server=DESKTOP-PC;Database=test_db;UID=yama;PWD=123456;"
```

理屈としては、同じローカルホスト内であっても、ホスト名を指定して接続する以上は、アクセスするクライアントに対しても接続の許可を与えないとならないということでしょうか…（詳しくはわかりません）。
外部サーバに接続する場合は、このあたりを上手く設定すれば良さそうです。

**参考サイト**
・[MySQL を外部接続できるようにする](https://yosugi.hatenablog.jp/entry/2013/06/23/185240)
・[Host xxx is not allowed to connect to this MySQL server の対応](https://zenn.dev/ryo_kawamata/articles/mysql-connect-error)

### 2-2-2. IPアドレスで指定する場合

自分のPCのIPアドレスは、**ipconfig**コマンドで確認することができます。

```
C:\>ipconfig
Windows IP 構成
（中略）
イーサネット アダプター イーサネット:
   接続固有の DNS サフィックス . . . . .:
   リンクローカル IPv6 アドレス. . . . .:
   IPv4 アドレス . . . . . . . . . . . .: 192.168.3.5
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   デフォルト ゲートウェイ . . . . . . .: 192.168.3.1
（以下略）
```

上記のうち、**IPv4 アドレス**が自分のPCの**IPアドレス**（プライベートIPアドレス）になります。

確認できたIPアドレス「192.168.3.5」をServerに指定して接続してみますが、IPアドレスの場合も前例のホスト名の場合と同様に、先に、接続するためのユーザーを作成します。

```
mysql> create user 'tama'@'192.168.3.5' identified by '123456';
Query OK, 0 rows affected (0.28 sec)

mysql> grant all on *.* to 'tama'@'192.168.3.5';
Query OK, 0 rows affected (0.18 sec)
```

前例と基本的に同じですが、GRANT文においては、作成したユーザーに対して、全てのデータベースの全てのテーブル（`*.*`）に対して、全ての権限（`grant all`）を与えています。

**ConnectionStringプロパティ**の部分には次のように記載します。これでうまく動作すると思います。

```vb:ServerにIPアドレスを指定する
cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};Server=192.168.3.5;Database=test_db;UID=tama;PWD=123456;"
```

## 2-3. Port（ポート番号）の指定

**Port**（ポート番号）の指定については次のように記載します。

```vb:
Port=3306
```

MySQLのポート番号はデフォルトで`3306`です。
デフォルトのままであれば、Port番号の指定は無くとも構いません。

## 2-4. Database（データベース名）の指定

**Database**（データベース名）の指定については次のように記載します。これ以上何も言うことはありません。

```vb:
Database=test_db
```

## 2-5. ユーザー名とパスワードの指定

**User**（ユーザー名）と**Password**（パスワード）の指定については次のように記載します。

```vb
＜例1＞
User=tama
Password=123456

＜例2＞
UID=tama
PWD=123456
```

UserはUIDと書くこともでき、PasswordはPWDと書くこともできます。

## 2-6. Charset（文字セット）の指定

最後に、**Charset**（文字セット）の指定です。
次の例ではクライアント側の文字コードをSHIFT_JISと指定していることになります。
Windows VBAでは、`sjis`又は`cp932`としておけば間違いないところと思います。

```vb
Charset=sjis
```

[参考とさせていただいたサイト](https://excelwork.info/excel/databasemysql/)によると、クライアント側の文字コードとデータベース側の文字コードが異なる場合に、クライアント側の文字コードを指定するとしています。

つまり、Charsetはあくまで、クライアント側の設定と言うことになります。
MySQLデータベースの文字コードがUTF-8（`utf8mb4`）であっても、SHIFT_JIS（`cp932`）であっても、**Charset**（文字セット）の指定には何ら影響はありません（次の表を見ればわかります）。


### 2-6-1. 文字コードの設定と読取り内容の確認

Driver及びCharsetの設定がどのように影響するかについて、確認した内容は次の表のとおりです。

|MySQL DBの文字コード|Driverの指定|Charsetの指定|カラム名読み込み結果|レコード読み込み結果|ADOXカラム名読み込み結果|
|---|---|---|---|---|---|
|utf8mb4 / cp932|Unicode Driver|指定なし|正常|正常|文字化け|
|utf8mb4 / cp932|Unicode Driver|utf8mb4|正常|文字化け|文字化け|
|utf8mb4 / cp932|Unicode Driver|utf8|正常|<font color="red">正常</font>|文字化け|
|utf8mb4 / cp932|Unicode Driver|sjis / cp932|正常|正常|正常|
|utf8mb4 / cp932|ANSI Driver|指定なし|文字化け|正常|<font color="red">正常</font>|
|utf8mb4 / cp932|ANSI Driver|utf8mb4|文字化け|文字化け|文字化け|
|utf8mb4 / cp932|ANSI Driver|utf8|文字化け|文字化け|文字化け|
|utf8mb4 / cp932|ANSI Driver|sjis / cp932|文字化け|正常|正常|

MySQLのデータベースの文字コードは、`utf8mb4`で指定しても`cp932`で指定しても結果は変わらないのでまとめて記載しています。
<font color="red">赤字</font>のところは予想外の結果です（何でだろう？）。
最後の「ADOXカラム名読み込み」は、**ADOX**の**[Tablesコレクション](https://docs.microsoft.com/ja-jp/sql/ado/reference/adox-api/tables-collection-adox?view=sql-server-ver15)**から得たカラム名の確認結果です（具体的なことは[最後](#3-7-テーブルが存在するか否かを確認する)に取り上げます）。

### 2-6-2. 文字コードの設定による挙動のまとめ

①　MySQL DBにおいて設定している文字コードは、VBAの結果に影響を及ぼさない。
②　**ANSI Driver**を選択すると、DB名、テーブル名、カラム名の読取りに文字化けが生じる（データはUTF-8で取得されるがVBAでは読み込めないため）。
③　**Unicode Driver**を選択すると、DB名、テーブル名、カラム名の文字化けは生じない。
④　Charsetの指定に、**utf8mb4（UTF-8）**を選択するとレコードに文字化けが生じる（ただし、Unicode DriverでUTF-8を指定すると何故か正常に読み取れる）。
⑤　ADOXを使用する際は、Charsetを**SHIFT_JIS（cp932）**と指定する必要がある。

結論として、**Driver**は**MySQL ODBC 8.0 Unicode Driver**を選択して、**Charset**は**sjis（cp932）**を選択すれば問題はないということになります。

**参考サイト**
[ODBCドライバと各社RDBクライアント文字コードの関係](https://www.idearu.info/article/data/ds1095)
[VBA Unicode 文字の入力や変換、読み込みについて](https://www.tipsfound.com/vba/04012)

# 3. 主なSQL構文によるソースコード例

以下、テーブルの操作を中心に、主要なSQL文を書いておきます。

## 3-1. SELECT文（レコードの取得）

SELECT文の例は最初に挙げているので、少し形を変えて、カラム名も取得してExcelのシートに書き出すソースコードを貼っておきます。

```vb
'SELECT文（レコード内容の取得）
Sub ConnectToMysqlDatabase_SELECT()
    'ADOを使用してMySQLに接続
    Dim cn As New ADODB.Connection 'Connectionオブジェクトのインスタンスを生成
    cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};" & _
                          "Server=localhost;" & _
                          "Database=test_db;" & _
                          "User=yama3;" & _
                          "Password=123456"
    cn.Open
    
    'SELECT文の実行
    Dim rs As New ADODB.Recordset 'Recordsetオブジェクトのインスタンスを生成
    rs.Open "SELECT * FROM 商品リスト", cn
    
    '出力先のワークシートオブジェクトを取得
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    
    'カラム名をワークシートに書き込む
    Dim i As Long, j As Long
    i = 1
    For j = 1 To rs.Fields.count
        ws.Cells(i, j) = rs(j - 1).Name
    Next j
    
    'レコードをワークシートに書き込む
    Do Until rs.EOF
        i = i + 1
        For j = 1 To rs.Fields.count
            ws.Cells(i, j) = rs(rs(j - 1).Name)
        Next j
        rs.MoveNext
    Loop

    'メモリの解放
    rs.Close: Set rs = Nothing
    cn.Close: Set cn = Nothing
End Sub
```

出力結果は次のようになります。
![2021-02-24 215735.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/a01968db-e65a-8235-1d4d-5e739d221f84.png)

上記のコードでは、カラム数を取得するために[Fieldsコレクション](https://docs.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/fields-collection-ado)を、カラム名を取得するために[Fieldオブジェクト](https://docs.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/field-object-ado)を使用しています。
ADOでよく使用するプロパティは次のあたりです。

|名称|内容|備考|
|---|---|---|
|[Countプロパティ](https://docs.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/count-property-ado)|Fieldsコレクション内のFieldオブジェクト数を示す|Fieldsコレクションのプロパティ|
|[Nameプロパティ](https://docs.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/name-property-ado)|フィールド名（カラム名）を示します|Fieldオブジェクトのプロパティ|
|[Typeプロパティ](https://docs.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/type-property-ado)|データ型を[DataTypeEnum](https://docs.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/datatypeenum)で示します|Fieldオブジェクトのプロパティ|

## 3-2. CREATE TABLE文（テーブルの作成）

テーブルの作成には[CREATE TABLE文](https://www.dbonline.jp/mysql/table/index1.html)を使用します。

```vb
'CREATE TABLE文（テーブル作成）
Sub ConnectToMysqlDatabase_CreateTable()
    'ADOを使用してMySQLに接続
    Dim cn As New ADODB.Connection 'Connectionオブジェクトのインスタンスを生成
    cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};" & _
                          "Server=localhost;" & _
                          "Database=test_db;" & _
                          "User=yama3;" & _
                          "Password=123456;"
    cn.Open
    
    'CREATE TABLE文の実行
    Dim cm As New ADODB.Command 'Commandオブジェクトのインスタンスを生成
    cm.ActiveConnection = cn
    cm.CommandText = "CREATE TABLE 買物リスト(" & _
                        "ID INT PRIMARY KEY," & _
                        "品名 VARCHAR(20)," & _
                        "区分 VARCHAR(10)," & _
                        "単価 DECIMAL(10)," & _
                        "購入数 SMALLINT," & _
                        "購入日 DATE)"
    cm.Execute
    
    'メモリの解放
    Set cm = Nothing
    cn.Close: Set cn = Nothing
End Sub
```

実行結果をコマンドプロンプトから確認すると、次のようなテーブルが作成されていることが分かります。

```:コマンドプロンプト
mysql> show create table 買物リスト\G
*************************** 1. row ***************************
       Table: 買物リスト
Create Table: CREATE TABLE `買物リスト` (
  `ID` int NOT NULL,
  `品名` varchar(20) DEFAULT NULL,
  `区分` varchar(10) DEFAULT NULL,
  `単価` decimal(10,0) DEFAULT NULL,
  `購入数` smallint DEFAULT NULL,
  `購入日` date DEFAULT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.07 sec)
```

PRIMARY KEY制約を付加すると、自動的にNOT NULL制約も付加されています。また、明示されていませんがUNIQUE制約も内包されています。

## 3-3. INSERT文（レコードの追加）

レコードの追加には[INSERT文](https://www.dbonline.jp/mysql/insert/index1.html)を使用します。

### 3-3-1. レコードを1つ追加するINSERT文

まず、レコードを1つ追加する場合です。

```vb
'INSERT文（データの追加）
Sub ConnectToMysqlDatabase_InsertInto1()
    'ADOを使用してMySQLに接続
    Dim cn As New ADODB.Connection 'Connectionオブジェクトのインスタンスを生成
    cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};" & _
                          "Server=localhost;" & _
                          "Database=test_db;" & _
                          "User=yama3;" & _
                          "Password=123456;"
    cn.Open
    
    'INSERT文の実行
    Dim cm As New ADODB.Command 'Commandオブジェクトのインスタンスを生成
    cm.ActiveConnection = cn
    cm.CommandText = "INSERT INTO 買物リスト VALUES (1, 'ほうれんそう', '野菜', 150, 2, '2021-2-25')"
    cm.Execute
    
    'メモリの解放
    Set cm = Nothing
    cn.Close: Set cn = Nothing
End Sub
```

コマンドプロンプトから確認すると、次のようにレコードが追加されているのがわかります。

```:コマンドプロンプト
mysql> select * from 買物リスト;
+----+--------------+------+------+--------+------------+
| ID | 品名         | 区分 | 単価 | 購入数 | 購入日     |
+----+--------------+------+------+--------+------------+
|  1 | ほうれんそう | 野菜 |  150 |      2 | 2021-02-25 |
+----+--------------+------+------+--------+------------+
1 row in set (0.04 sec)
```

### 3-3-2. Excelシートからまとめてレコードを追加するINSERT文

次に、複数のレコードを一気に追加する場合のコードです。
ここでは、次のようなExcelシートの表を、MySQLデータベースに格納してみます。
![2021-02-24 234850.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/1774a90c-c743-6268-12b6-cb7da0ae3b58.png)

コードは次のとおりです。

```vb
'INSERT文（データの追加）
Sub ConnectToMysqlDatabase_InsertInto2()
    
    'ADOを使用してExcelファイルに接続
    Dim xlCn As New ADODB.Connection
    xlCn.ConnectionString = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" & _
                            "DBQ=" & ThisWorkbook.FullName & ";" & _
                            "ReadOnly=1"
    xlCn.Open
    
    'ExcelのシートをSELECT文で読み込んでINSERT文を作成
    Dim xlRs As New ADODB.Recordset
    xlRs.Open "SELECT * FROM [サンプルテーブル$]", xlCn
    Dim sqlStr As String: sqlStr = "INSERT INTO 買物リスト VALUES " 'これに続けてテーブル内容を列挙していく
    Dim comma As String: comma = ""
    Do Until xlRs.EOF
        sqlStr = sqlStr & comma & "(" & xlRs("ID") & ", '" & xlRs("品名") & "', '" & xlRs("区分") & "', " & xlRs("単価") & ", " & xlRs("購入数") & ", '" & xlRs("購入日") & "')"
        If comma = "" Then comma = ", "
        xlRs.MoveNext
    Loop
    
    'ADOを使用してMySQLに接続
    Dim cn As New ADODB.Connection 'Connectionオブジェクトのインスタンスを生成
    cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};" & _
                          "Server=localhost;" & _
                          "Database=test_db;" & _
                          "User=yama3;" & _
                          "Password=123456;"
    cn.Open
    
    'INSERT文の実行
    Dim cm As New ADODB.Command 'Commandオブジェクトのインスタンスを生成
    cm.ActiveConnection = cn
    cm.CommandText = sqlStr
    cm.Execute
    
    'メモリの解放
    xlRs.Close: Set xlRs = Nothing
    xlCn.Close: Set xlCn = Nothing
    Set cm = Nothing
    cn.Close: Set cn = Nothing
End Sub
```

レコード1つにき1つのINSERT文を発行しても良いのですが、それだと処理に時間が掛かってしまうので、[複数のデータをまとめて追加するINSERT文](https://www.dbonline.jp/mysql/insert/index1.html#section5)を使用して、一括でデータを追加しています。

コマンドプロンプトから確認すると、次のようにレコードが追加されています。

```:コマンドプロンプト
mysql> select * from 買物リスト;
+----+--------------+------+------+--------+------------+
| ID | 品名         | 区分 | 単価 | 購入数 | 購入日     |
+----+--------------+------+------+--------+------------+
|  1 | ほうれんそう | 野菜 |  150 |      2 | 2021-02-25 |
|  2 | にんじん     | 野菜 |   70 |      3 | 2021-02-09 |
|  3 | りんご       | 果物 |  150 |      2 | 2021-02-28 |
|  4 | みかん       | 果物 |   40 |     10 | 2021-02-01 |
|  5 | キャベツ     | 野菜 |  180 |      1 | 2021-02-28 |
|  6 | トマト       | 野菜 |   50 |      3 | 2021-02-28 |
|  7 | じゃがいも   | 野菜 |   50 |     15 | 2021-01-30 |
|  8 | バナナ       | 果物 |  300 |      2 | 2021-02-03 |
|  9 | メロン       | 果物 | 1500 |      1 | 2021-02-26 |
+----+--------------+------+------+--------+------------+
9 rows in set (0.00 sec)
```

## 3-4. UPDATE文（レコードの更新）

レコードの内容を更新するには[UPDATE文](https://www.dbonline.jp/mysql/insert/index7.html)を使います。

```vb
'UPDATE文（レコードの更新）
Sub ConnectToMysqlDatabase_UPDATE()
    'ADOを使用してMySQLに接続
    Dim cn As New ADODB.Connection 'Connectionオブジェクトのインスタンスを生成
    cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};" & _
                          "Server=localhost;" & _
                          "Database=test_db;" & _
                          "User=yama3;" & _
                          "Password=123456;"
    cn.Open
    
    'UPDATE文の実行
    Dim cm As New ADODB.Command 'Commandオブジェクトのインスタンスを生成
    cm.ActiveConnection = cn
    cm.CommandText = "UPDATE 買物リスト SET 購入数 = 20 WHERE ID = 7"
    cm.Execute
    
    'メモリの解放
    Set cm = Nothing
    cn.Close: Set cn = Nothing
End Sub
```

コマンドプロンプトで確認すると、IDが`7`のレコードの購入数が`15`から`20`に更新されていることがわかります。

```:コマンドプロンプト
mysql> select * from 買物リスト;
+----+--------------+------+------+--------+------------+
| ID | 品名         | 区分 | 単価 | 購入数 | 購入日     |
+----+--------------+------+------+--------+------------+
|  1 | ほうれんそう | 野菜 |  150 |      2 | 2021-02-25 |
|  2 | にんじん     | 野菜 |   70 |      3 | 2021-02-09 |
|  3 | りんご       | 果物 |  150 |      2 | 2021-02-28 |
|  4 | みかん       | 果物 |   40 |     10 | 2021-02-01 |
|  5 | キャベツ     | 野菜 |  180 |      1 | 2021-02-28 |
|  6 | トマト       | 野菜 |   50 |      3 | 2021-02-28 |
|  7 | じゃがいも   | 野菜 |   50 |     20 | 2021-01-30 |
|  8 | バナナ       | 果物 |  300 |      2 | 2021-02-03 |
|  9 | メロン       | 果物 | 1500 |      1 | 2021-02-26 |
+----+--------------+------+------+--------+------------+
9 rows in set (0.01 sec)
```

## 3-5. DELETE文（レコードの削除）

レコードの削除には[DELETE文](https://www.dbonline.jp/mysql/insert/index10.html)を使います。

### 3-5-1. レコードの一部を削除するDELETE文

```vb
'DELETE文（レコードの一部削除）
Sub ConnectToMysqlDatabase_Delete1()
    'ADOを使用してMySQLに接続
    Dim cn As New ADODB.Connection 'Connectionオブジェクトのインスタンスを生成
    cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};" & _
                          "Server=localhost;" & _
                          "Database=test_db;" & _
                          "User=yama3;" & _
                          "Password=123456;"
    cn.Open
    
    'DELETE文の実行
    Dim cm As New ADODB.Command 'Commandオブジェクトのインスタンスを生成
    cm.ActiveConnection = cn
    cm.CommandText = "DELETE FROM 買物リスト WHERE 区分 = '野菜'"
    cm.Execute
    
    'メモリの解放
    Set cm = Nothing
    cn.Close: Set cn = Nothing
End Sub
```

実行結果をコマンドプロンプトで確認すると、次のとおりです。

```:コマンドプロンプト
mysql> select * from 買物リスト;
+----+--------+------+------+--------+------------+
| ID | 品名   | 区分 | 単価 | 購入数 | 購入日     |
+----+--------+------+------+--------+------------+
|  3 | りんご | 果物 |  150 |      2 | 2021-02-28 |
|  4 | みかん | 果物 |   40 |     10 | 2021-02-01 |
|  8 | バナナ | 果物 |  300 |      2 | 2021-02-03 |
|  9 | メロン | 果物 | 1500 |      1 | 2021-02-26 |
+----+--------+------+------+--------+------------+
4 rows in set (0.02 sec)
```

### 3-5-2. レコードの全部を削除するDELETE文

```vb
'DELETE文（レコードの全部削除）
Sub ConnectToMysqlDatabase_Delete2()
    'ADOを使用してMySQLに接続
    Dim cn As New ADODB.Connection 'Connectionオブジェクトのインスタンスを生成
    cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};" & _
                          "Server=localhost;" & _
                          "Database=test_db;" & _
                          "User=yama3;" & _
                          "Password=123456;"
    cn.Open
    
    'DELETE文の実行
    Dim cm As New ADODB.Command 'Commandオブジェクトのインスタンスを生成
    cm.ActiveConnection = cn
    cm.CommandText = "DELETE FROM 買物リスト"
    cm.Execute
    
    'メモリの解放
    Set cm = Nothing
    cn.Close: Set cn = Nothing
End Sub
```

実行結果をコマンドプロンプトで確認すると、次のとおりテーブルの中身が空（Empty）であることがわかります。

```:コマンドプロンプト
mysql> select * from 買物リスト;
Empty set (0.00 sec)
```

## 3-6. DROP TABLE文（テーブルの削除）

テーブルそのものを削除する場合は[DROP TABLE文](https://www.dbonline.jp/mysql/table/index4.html)を使います。

```vb
'DROP TABLE文（テーブル削除）
Sub ConnectToMysqlDatabase_DropTable()
    'ADOを使用してMySQLに接続
    Dim cn As New ADODB.Connection 'Connectionオブジェクトのインスタンスを生成
    cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};" & _
                          "Server=localhost;" & _
                          "Database=test_db;" & _
                          "User=yama3;" & _
                          "Password=123456;"
    cn.Open
    
    'DROP TABLE文の実行
    Dim cm As New ADODB.Command 'Commandオブジェクトのインスタンスを生成
    cm.ActiveConnection = cn
    cm.CommandText = "DROP TABLE 買物リスト"
    cm.Execute
    
    'メモリの解放
    Set cm = Nothing
    cn.Close: Set cn = Nothing
End Sub
```

実行結果をコマンドプロンプトで確認すると、次のように「買物リスト」テーブルが存在しないことが確認できます。

```:コマンドプロンプト
mysql> select * from 買物リスト;
ERROR 1146 (42S02): Table 'test_db.買物リスト' doesn't exist
```

## 3-7. テーブルが存在するか否かを確認する

少し方向性が異なりますが、最後に、**データベース内にテーブルが存在するか否かの確認を行うコード**を書いておきます。
ここでは、データベースのテーブル一覧を取得するために[ADOXオブジェクト](https://docs.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/adox-api-reference)を使用します。
以下の例では、事前に、`Microsoft ADO Ext. 6.0 for DDL and Security`というライブラリの[参照設定](https://qiita.com/t-yama-3/items/f783527c6463a28ecc63#4-1-adox%E3%81%AE%E4%BD%BF%E7%94%A8)をしています。

```vb
'テーブルが存在するかの確認を実行
Sub IsExistMysqlTableTest()
    Debug.Print IsExistMysqlTable("test_db", "買物リスト")
End Sub

'テーブルが存在するか否かを確認する関数（戻り値：True=存在する, False=存在しない）
Function IsExistMysqlTable(dbName As String, tblName As String) As Boolean
    Dim cn As New ADODB.Connection 'Connectionオブジェクトのインスタンスを生成
    cn.ConnectionString = "Driver={MySQL ODBC 8.0 Unicode Driver};" & _
                          "Server=localhost;" & _
                          "Database=" & dbName & ";" & _
                          "User=yama3;" & _
                          "Password=123456;" & _
                          "charset=cp932;" 'クライアント側の文字コードを指定
    cn.Open
    
    Dim ct As New ADOX.Catalog: ct.ActiveConnection = cn 'Catalogオブジェクトを現在のDBに関連付け
    Dim tbl As Table 'テーブルオブジェクトを格納する変数
    IsExistMysqlTable = False '初期値を明示（書かなくともFalse）

    For Each tbl In ct.Tables 'CatalogオブジェクトのTablesコレクションを1つずつ取得
        If tbl.Type = "TABLE" And StrComp(tbl.Name, tblName, vbTextCompare) = 0 Then 'TableオブジェクトのTypeプロパティとNameプロパティで一致するかを確認
            IsExistMysqlTable = True
            Exit For
        End If
    Next
    
    Set ct = Nothing 'Catalogオブジェクトの解放
    cn.Close: Set cn = Nothing 'Connectionオブジェクトの解放
End Function
```

### 3-7-1. ADOXのTableオブジェクトについて

ADOXの[Catalogオブジェクト](https://docs.microsoft.com/ja-jp/sql/ado/reference/adox-api/catalog-object-adox?view=sql-server-ver15)には、データベースのコレクション (テーブル、ビュー、ユーザーなど) が格納されます。
ここでは、[Tablesコレクション](https://docs.microsoft.com/ja-jp/sql/ado/reference/adox-api/tables-collection-adox?view=sql-server-ver15)の[Tableオブジェクト](https://docs.microsoft.com/ja-jp/sql/ado/reference/adox-api/table-object-adox?view=sql-server-ver15)が持っている次のプロパティを使用して、テーブルの存否を確認しています。

|プロパティ名|内容|備考|
|---|---|---|
|[Typeプロパティ](https://docs.microsoft.com/ja-jp/sql/ado/reference/adox-api/type-property-table-adox?view=sql-server-ver15)|テーブルの種類を指定する文字列値を返す|"TABLE"、"SYSTEM TABLE"、"GLOBAL TEMPORARY"など|
|[Nameプロパティ](https://docs.microsoft.com/ja-jp/sql/ado/reference/adox-api/name-property-adox?view=sql-server-ver15)|テーブル名を示す|（大文字と小文字の区別がされていないようです）|

### 3-7-2. 取得されるテーブル名の文字コードについて

上記ソースコードのConnectionStringプロパティでは、`charset=cp932`と指定しています（`charset=sjis`でもよい）。
これを指定しないと、テーブル名が文字化けして、正しく読み取ることができません。

なお取得される文字コードは、使用するドライバ（`MySQL ODBC 8.0 Unicode Driver`又は`MySQL ODBC 8.0 ANSI Driver`）によっても若干異なります。
この挙動については、前掲「[2-6-1. 文字コードの設定と読取り内容の確認](#2-6-1-文字コードの設定と読取り内容の確認)」のとおりです。

# さいごに

ドライバの選択や、文字コードについては調べても分からないことが多かったので、手元で確認してみた結果を書いておきました。
本記事は個人的な備忘にすぎませんが、何らかのお役に立つことがあれば幸いです。