プログラミング経験０の僕がAccessVBAを使ってみた。

#0.はじめに
**”🚨プログラミング経験０🚨”**

IT業界に飛び込んで一か月。
プログラミングのプの字もわからない僕が最初に出会ったのが"Access VBA"でした。

「"Access"って何だろう？」「"VBA"って何だろう？」

右も左もわからない状態でのスタートを切った僕が、事前知識として知っておきたかったことをまとめました。

これからAccessVBAを使う方、始める方の一助になれれば幸いです。

**・開発環境**
OS:Windows10
Accessのバージョン：Access2016

#1．VBAを書き始める前に。

##▼VBE(Visual Basic Editor)を起動する方法
Alt + F11 を押すことでVBE（VBAを記述するエディタ）を起動できます。このショートカットキーでAccessの画面とVBEの画面を素早く移動できます。ExcelのVBEも同様の方法で起動できます。これを知っているだけで作業速度が格段にあがります。

##▼変数の宣言を強制するように設定する
VBAのデフォルト設定では、変数の宣言をしていなくても使用することができてしまいます。
この場合、バグが発生する原因になるのであらかじめ、変数の宣言を強制しておきましょう。

VBE画面のツールバーから「ツール」→　「オプション」をクリックします。

![キャプチャ6.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/54c0fe27-d859-d5a0-2f27-7df9befea31d.jpeg)


変数の宣言を強制するにチェックを入れます。
![キャプチャ7.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/276f5a2c-a925-0fc5-b041-3199d2691ea5.jpeg)

これで、VBAの先頭に自動的に Option Explicit が挿入されるようになり、変数の宣言を強制させることができます。

#2．実際にVBAを書いていこう。

##▼変数の宣言
変数の宣言はデータ型によって宣言する必要があります。
Variant型を使えば変数の中身は制限されませんが、数値にはIntegerかLong、文字列にはStringなど、決められた宣言を適用したほうが処理が速くなります。
また、変数内部のデータが分かりやすくなるため修正・変更がしやすくなります。
特定の理由がない限りは、変数のデータ型に合った宣言を心がけましょう。

|   データ型     |宣言|    　範囲         |
|:----------------------:|:------------:|:------------:|
| バイト型       |        Byte |     0～255     |
| ブール型     |      Bool |    真（True）偽（False）    |
| 整数型     |        	Integer |     -32,768～32,767     |
| 長整数型         |          	Long |      	-2,147,483,648～2,147.483,647         |
| 通貨型   |     Currency |   -922,337,203,685,477.5808～922,337,203,685,477.5807    |
| 日付型	  |     Date |   	西暦100年1月1日～西暦9999年12月31日    |
|オブジェクト型 |     Object |   オブジェクトを参照するデータ型   |
| 文字列型  |     String |   0～2ＧＢ    |
| バリアント型  |     Variant |   すべてのデータを扱えるデータ型で0～2ＧＢ   |


##▼関数
関数は数が多くすべてを覚えるのはなかなか難しいです。中でも使用頻度が高そうな関数を紹介します。

**・メッセージボックスを表示する”msgbox関数”**
書式：MsgBox"文字列",ボタンと記号の種類,タイトル
![キャプチャ13.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/536df2d3-831d-c891-039e-66e6d8aeca7b.jpeg)

このコードを実行すると次のメッセージボックスが表示されます。
![キャプチャ14.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/11c9f03d-1bda-a9fe-27a3-b07c9f477512.jpeg)

ボタンや記号の種類はメッセージボックスの用途によって使い分けましょう。
[MsgBox関数の使い方][link-3]
[link-3]:https://www.moug.net/tech/exvba/0100033.html

**・文字列内の検索文字列を置換文字列に置き換える”Replace関数”**
書式：Replace(文字列, 検索文字列, 置換文字列, 開始位置, 置換回数, 比較モード)

![キャプチャ10.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/e2d9139e-a12f-4169-3e64-2c1cdd98b70f.jpeg)

変数tmpに格納されている値の"カンマ"を改行コード"vbCrlf"に変換してメッセージボックスに表示させてみます。

コードを実行すると、メッセージボックスが2回表示され、カンマが改行されていることが分かります。

1回目
![キャプチャ11.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/8e6df3d2-a729-0a6e-bb8d-1f7e184872e4.jpeg)

2回目
![キャプチャ12.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/016c0194-cbd2-ce0f-f1f4-05ead2a94359.jpeg)

**・2つの文字列を比較する”StrComp関数”**
書式：StrComp(文字列1, 文字列2, 比較モード)

![キャプチャ15.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/f02dd53e-7dd2-ca73-8e1e-75df1c775c89.jpeg)

二つの文字列が完全に一致しているかを判断することができます。

この場合、”文字列不一致！！”のメッセージボックスが表示されます。
![キャプチャ16.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/46315438-c58e-bf99-5461-c00ff5312709.jpeg)


**・文字列から検索文字列を検索する”InStr関数”**
書式：InStr(開始位置, 文字列, 検索文字列, 比較モード)

対象の文字列から、検索文字列が何番目にあるかを返します。
検索文字列が対象の文字列から見つからなかった場合は０を返します。

![キャプチャ17.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/6e002252-b4f0-edcd-8791-68e81dd4f845.jpeg)

この場合メッセージボックスが2回表示され、一回目は"ｄ"の位置を左からカウントして"４"、二回目は"あ"が文字列にないため"０"と表示されます。

1回目
![キャプチャ18.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/59562ac0-dcdc-31b8-9d98-d23c862b8264.jpeg)

2回目
![キャプチャ19.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/7cf844b9-2b19-22a7-a5bf-2070b24dfc95.jpeg)

**・文字列の文字数を返す”Len関数”**
書式：Len(文字列)

len関数は変数や文字列の文字数を返します。
![キャプチ21.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/f753b392-50df-cd8c-339e-a9da051aadf0.jpeg)

この場合、26と表示されます。
![キャプチャ22.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/961f4bcd-03a9-cec2-c549-325faa963134.jpeg)

**・指定したフィールドのデータ数を求める”DCount関数”**
書式：DCount(フィールド, テーブル, 条件)

指定したテーブル上に、条件が一致するレコード数を返します。
この場合、T_顧客情報の年齢が40歳以上のレコード数がメッセージボックスに表示されます。
![キャプチャ24.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/c93342b2-2745-6f67-8c34-6921cb4c922b.jpeg)


**・指定したフィールドの特定のデータを求める”DLookup関数”**
書式：DLookup(知りたいフィールド名, テーブル, 条件)

指定したテーブル上で、指定した条件のレコードのフィールドの値を返します。
この場合、顧客コードが”B12368”の顧客の氏名が変数tmpに格納されます。

![キャプチャ26.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/a79a1214-6c96-616c-e69c-3c33251a49f3.jpeg)

**・評価対象がNullの場合にTrue、それ以外の場合にFalseを返す”IsNull関数”**
書式：IsNull(評価対象)
![キャプチャ27.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/0c0baf88-a75c-9da6-1fb6-c3bb5e7f8665.jpeg)

この場合、変数tmpがNullなので、メッセージボックスが表示されます。
変数にテーブルのデータを代入していて、Nullかそうでないかで処理を分けたい時などに活用できます。

関数は上記以外にも数多く存在します。処理に必要な関数を見極めて使用しましょう。
[Access VBA 関数一覧参考ページ][link-2]
[link-2]:https://sites.google.com/site/accessclassroom/access_kannsuu_itiran



##▼コメントは必ず書いておく。
当たり前のことですが、コメントを書いておくことは重要な作業です。
変数の宣言、処理内容ごとにコメントを記述しておくと後々変更を加えるときに可読性が高くなって便利です。

※コメントの記述方法は、コードや文章の前にシングルコーテーション（'）を書きます。文字色が緑色になったら無事にコメントアウトできています。

```
'################################################################################
'
'ボタン押下時処理
'
'################################################################################
Private Sub cmd_button_Click()

    Set db = CurrentDb
    Set rs = db.OpenRecordset("テーブル名", dbOpenDynaset)'ダイナセットで開く
    Set rs = サブフォーム名.Form.Recordset'レコードセット
   
    DoCmd.OpenForm "フォーム名"'フォームを開く

```

処理中にもコメントを書いておけば、バグが出たとき、変更があった場合などに対応しやすくなります。他の人が見ても分かるようにVBAを書いていくことが可読性UPに繋がります。

```

Set db = CurrentDb
Set rs = db.OpenRecordset("テーブル名", dbOpenDynaset)'ダイナセットで開く
Set rs = サブフォーム名.Form.Recordset'レコードセット

Dim name_tmp As String

If rs.RecordCount = 0 Then Exit Sub　'レコード件数一件の場合の処理

Else
    name_tmp = rs.Fields("氏名")
    rs.MoveNext
        If rs.EOF Then '選択レコードが最終行の時、カレントレコードを一番上に持っていく
            rs.MoveFirst
        End If
End if

```

##▼標準モジュールとクラスモジュールを使い分ける。
**・標準モジュール**

例えばフォーム１、フォーム２、フォーム３があったと仮定します。各フォームでの作業はそれぞれ違いますが、同じ処理を必要とする場合、（同じ関数を使う場合）は標準モジュールに記入することで、どのフォームのクラスモジュールからでも処理や、関数を呼び出すことができます。

```

'特定の文字の個数検索
Function CCount(FV As Variant, findChr As String) As Integer
    Dim i As Integer

    For i = 1 To Len(Nz(FV, ""))
        CCount = CCount - (Mid(FV, i, Len(findChr)) = findChr)
    Next

End Function

```
これで、どのフォームのクラスモジュールでも”CCount”という特定の文字の個数検索をするオリジナルの関数が使用できるようになります。

![キャプチャ10.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/54193a22-8d88-9fd1-f649-21cb53b2e032.jpeg)

また、標準モジュールに変数をPublicで宣言することで、フォームからフォームへ、変数に代入した値を保持することができます。
例えばフォーム１で算出した結果をフォーム２に表示させる、など様々な場面で役に立ちます。

この際の注意点はクラスモジュールの変数宣言とバッティングしてしまう可能性があることです。
（例えば標準モジュールで'Public cnt As Longを宣言し、クラスモジュールではDim cnt As Longを宣言すると宣言が重複しています、とエラーが発生する）
標準モジュールに変数を宣言する場合は、一意の名称になるように注意が必要です。

**・クラスモジュール**
クラスモジュールにはイベントプロシージャ（イベントごとの処理）ごとにVBAが区切られていますが、クラスモジュール内で変数に代入した値を保持したい場合は、クラスモジュールの一番上にPublic変数で記入することで値を保持することができます。

```
Option Compare Database
Option Explicit

public cnt As Long

```

クラスモジュール内でも同じ計算や、処理をすることがあります。
この場合Functionプロシージャを作成することで同じVBAを何度も書く手間が省けますし、修正があった場合もFunctionプロシージャ内を変更するだけですべての処理に適応されるので、バグの発生も防げます。

```
--------------------------------------------------------------------------------------
'フォームが開くときの処理
Private Sub form_open(Cancel As Integer)

'テキストボックスにデータ呼び出し
txt（）

End Sub
---------------------------------------------------------------------------------------
'次のレコードに移動する処理
Private Sub cmd_Next_Record(Cancel As Integer)
rs.MoveNext

If rs.EOF Then
    rs.MoveFirst
End If
'テキストボックスにデータ呼び出し
txt（）

End Sub
---------------------------------------------------------------------------------------
function txt()

Me.txt1 = rs.Fields("氏名")
Me.txt2 = rs.Fields("部署名")
Me.txt3 = rs.Fields("年齢")

End Function
```

こうしておくことで”フォームを開くとき”、”次のレコードに移動するとき”、両方の処理でレコードのデータを指定のテキストボックスに表示させることができます。

##▼コード、文字列の改行
**・コードの改行**
SQLなど、一行が長くなってしまったときコードを改行したい時があります。その場合は「アンダーバー」+「半角スペース」を使用することでコードを改行することができます。

```
Dim strSQL AS String

strSQL = "SELECT name_id AS 管理番号 , address AS 住所 , phone_num AS 電話番号 , _ '←ココ！
FROM T_顧客情報 WHERE 年齢 < 40"

Me.サブフォーム.Form.Recordsource = strSQL

```

**・文字列の改行**
"vbLf","vbCrLf"もしくは"vbNewLine"を使用することで可能です。

```
MsgBox "ここで改行" &　vbLf　& "できます"
```

```
MsgBox "ここで改行" &　vbCrLf　& "できます"
```

```
MsgBox "ここで改行" &　vbNewLine　& "できます"
```

上の3つの例の結果はすべて下記になります。

```
ここで改行
できます
```
Excelなどにデータを出力する場合、vbCrlfでセル内の文字改行、vblfでセルの改行という処理になります。
改行コードは処理によって使い分けましょう。


##▼特定の文字を記入したい場合
[']、["]、[&]などを文字として記述したい場合は、ASCII文字コードを使用することで、記述することができます。

[ASCiiコード表参考ページ][link-1]

[link-1]:http://www.kanaya440.com/contents/script/vbs/others/ascii1.html

```
MsgBox "記号は" & Chr(39) & "と" & Chr(34) & "と" & Chr(38) &　"です"  
```
上記コードを実行すると、メッセージボックスに

```
記号は'と"と&です  
```
と表示されます。

#3．Excelとの連携

##▼Excel起動、操作
Excelへデータをエクスポートする際など、ExcelをAccessVBAから操作する場合、参照設定を変更する必要があります。

VBE画面のツールバー　「ツール」→「参照設定」をクリックします。

![キャプチャ8.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/74650934-2e6c-f4e4-e336-d1045d66a092.jpeg)

「Microsoft Excel XX.X Object Library」にチェックを入れます。（XX.XはExcelのバージョンによって異なります。）

![キャプチャ9.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/6b129fea-4627-b981-ee5c-e363d91a71b9.jpeg)

この設定をすることで、起動したExcel上のセルの指定などが行えるようになります。

```
Private Sub Export()
   
    Dim objEXE As Excel.Application
    Set objEXE = Excel.Application

    'ExcelVBAのコードを使用して、Excelの機能を使うことができる

    'Sheet名を指定
    objEXE.Worksheets("ページ１").Select   

    objEXE.Range("A1").Value = "100"
    objEXE.Range("A1").Copy Destination:=myExcel.Range("B1")

　　objEXE.ActiveWorkbook.Save   'エクセル・ファイルの上書き保存
    objEXE.ActiveWorkbook.Close  'エクセル・ファイルを閉じる
    objEXE.Quit                   '終了
    
    Set objEXE = Nothing

End Sub


```


このように、VBAから他のアプリケーションのオブジェクトを操作することを**「オートメーション」**といいます。

#4.デバッグ
VBAの実行時や処理中にエラーが発生した時は一行ずつ処理を確認していく方法が確実です。その際に役に立つデバッグ方法を紹介します。

**・ブレークポイントの設定と解除**
まず、ブレークポイントというものがあります。
これは、コードが記述してある行の、左端の灰色部分をクリックすることで設定、解除することができます。
設定すると灰色の部分に赤い丸が表示され、コード部分が赤い背景になります。

![キャプチャ.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/91589ad1-f9bf-dcc2-e8ba-0cb98dfb1983.jpeg)

この状態でVBAを実行すると、ブレークポイントを設定した行で処理が一時停止してくれます。

"F5キー"を押すことで次のブレイクポイントまで処理が進みます。

一時停止中に変数の上にマウスのカーソルを当てると、変数が現在格納している値をホバーで表示してくれます。

![キャプチャ2.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/37051edb-624b-21d8-604d-46e54711c4f4.jpeg)

黄色の矢印が、現在の処理の位置です。
前の処理に戻りたい場合は、黄色の矢印を戻したい行までドラッグすることで可能です。
エラーが発生した場合や、変数の内容が理想の結果ではなかった時、黄色の矢印を一度処理の前まで戻し、コードを変更してからもう一度処理を実行、、、を繰り返すことができます。

エラーが起きた箇所や処理全体にブレークポイントを設定することで、変数の値、ループの処理の過程などを見ていくことができ、間違ったコードや、足りないコードなどを知ることができます。

**・デバッグプリント**
上記の方法では変数に格納している値が長すぎると最後まで表示されなかったり、一度に多くの変数を確認したい場合などには向いていません。その場合は「Debug.Print」というコードを使うとデバッグが円滑に行えます。

まず、イミディエイトウィンドウという画面を表示させます。
VBE画面のツールバーの「表示」→「イミディエイトウィンドウ」をクリックします。

![キャプチャ3.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/c6e4a2c2-1a67-98a2-a028-09e7a7e60d16.jpeg)

もしくはショートカットキー、Ctrl + G　でも表示できます。

確認したい変数の前後など、確認したい箇所に「Debug.Print 変数名」をコードに書きます。
この場合、ブレークポイントが設定されている「Debug.Print cnt」になります。
この状態で処理を実行すると、変数cntの値がイミディエイトウィンドウに記述されていきます。

![キャプチャ4.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/a1e4681a-c500-1212-d318-60ce22a6a802.jpeg)

このように、変数「cnt」の値が１づつ増えているのが確認できます。
変数の値を文字出力してくれるので、正確に値が格納されているか判断できます。
特にループ処理の時などに重宝します。

デバックプリント以外でも、イミディエイトウィンドウは活用できます。
イミディエイトウィンドウ内に「？変数名」と記入すると、記入した変数名が現在格納している値を知ることができます。
変数以外にも、カレントパスなども知ることができます。

この場合「？intmsg」と記入しています。

![キャプチャ5.JPG](https://qiita-image-store.s3.amazonaws.com/0/174125/c9324d3d-5151-737d-0656-be3cac647bad.jpeg)


イミディエイトウィンドウを有効活用することで、エラーの原因、発生箇所などを素早く検知し、効率の良いデバッグ作業が行えます。

#5.感想
初めてプログラミングをする僕にとっては全てがわからないことだらけで勉強の毎日でした。
一口にAccessのツール開発といっても、VBAの書き方は勿論のこと、データベースの構造や設計、SQLの書き方などデータベース管理の幅広い知識が必要になってきます。

始めたての頃は、書籍やWebを使ってAccessの操作方法、VBAの記述方法を学習することで手一杯でしたが、事前知識としてAccessがデータベースを管理するツールだということを理解してデータベースの構造やSQLの知識を学ぶことが必至でした。

・必要な情報に焦点を当てて、情報を整理してから学習する。
・事前に構造を理解したうえで取り掛かる。

というプロセスがいかに重要かを思い知りました。

今回の反省点としては、データベースの構造や、データの登録形式など、理解が浅いままVBAを作成したがために、手戻りが発生することが多々ありました。

あらかじめ、この処理では何をしたいのか、どんな結果を得たいのかなど、大枠を明確にしてから詳細部分を作っていくことが重要だとわかりました。

打ち合わせや、ディスカッションなどには積極的に時間をかけて、内容を理解することが大事ですね。。。

プログラミングは実に楽しいものです。
難しい処理を完成させたときの達成感はたまりません。

常に現状で満足することなく、より効率の良いプログラミングとは？を念頭に置いて日々邁進していこうと思います！

PLUS ULTRA!!