Q.VBA を覚えたいんですけど、どうやって覚えたらいいでしょう?

* Amazon Access VBA 関連書籍情報

もうね、こんなこと言う人絶対いないのよ。今やデジタルネイティブ世代が普通に入社してくんのよ。VBA なんかもはや母語でしょ。言い過ぎか。意外とAmazon には VBA 本があった。
こちらも、歴史の教科書だと思って読んでいただけると助かります…

ほかのプログラミング言語をやっていた人なら、Helpの例を見ればそのHelpで説明している以外のことも解ってしまいますよね。IF文の書き方とか、関数の呼び方とか、変数の定義のしかたとか。
ところが、悲しいかな Access を使う人の多くはプログラミング経験がありません。そういう方々は高レベルな会議室などで質問をしても要領を得なかったり、常連のみなさんに「まずメールの書き方を覚えれ」とか冷たくあしらわれたりしますよね(^^;)(たしかに、質問する態度やメールの書き方などのマナーを覚えることはとても大事です、人としてダメな奴も多いですから)

なぼも昔は「冷たくあしらう派」でしたが、最近はそれじゃーダメだろう、と考えるようになりました。肝心の質問には一切答えず、「投稿のしかたを守れ」とだけしか言わないのって、あんまりにもタカビーあんたなに様じゃないですか?(でも、中にはほんとうにヒドイ投稿をする奴がいるのも確かです)
お偉い先生方は偉いんですからかまいませんが、なぼはまだまだライトユーザーの域を出ていませんから(^^;)そんなことはしたくないです。時々しちゃうけど。
コンピューターが一部のコンピューターの専門家、自分で CPU の設計までできちゃいそうな大学の研究室レベルの方々だけのものだった時代は終わったのです。知らないから覚えようとしている人の意欲をくじく真似は、この業界の先人として恥ずべき行為ですよね。
まぁ、中には親切にマナーまで教えてくれようとしている方に暴言を吐いたりする失礼な奴もいますが、(多分自分が誰だかわからないだろうと思っているんでしょうが、最近ネットでの誹謗中傷に対する世間の反応は敏感ですよ)そういう人には孤独を愛していただくことにして、このサイトでは「覚える気持ちがある」人を対象にしていきたいと思います。

おっと前置きが長いですね(^^;;)
まず、早めに覚えたほうがいいポイントをあげてみます。

  • IF・・・ELSE・・・ENDIF、変数の定義、値の代入
    VBA で記述する最大の目的は、「変数の利用と条件による分岐処理」だと思ってます。
    つまり、「ある項目の値が××のときAの処理、◎◎のときBの処理」と、状況によって行いたい処理が違う場合。
    処理の内容は関数を呼ぶだけとかフォームを開くだけとか簡単なものであっても、マクロでは対処しきれない場合があります。

    Dim Ret as Integer   ←1
    Ret = MsgBox(“処理していいですか?”,vbYesnoCancel)   ←2
    IF Ret = vbOK then   ←3
    Docmd.OpenForm(“処理用フォーム”)   ←4
    ELSE   ←5
    IF Ret = vbCancel then   ←6
    MsgBox(“キャンセルしました”)   ←7
    End If   ←8
    End If   ←9
    1. 「Ret」という名前の整数型の変数を定義している。MsgBox 関数戻り値である、「どのボタンを押されたか」という情報をとっておくのに使う
    2. MsgBox 関数を実行。「処理していいですか?」というメッセージを画面に出し、オペレータにOK、NO、キャンセルボタンのどれかを押してもらい、どれが押されたかを「Ret」という変数保存(値の代入)している
    3. もし、「Ret」の中身が「vbOK」だったら、という判断をしている。つまり、前のMsgBox関数を実行したとき、オペレータが押したのがOKボタンだったら、という意味。もしOKボタンを押した場合、4.の処理を実行することになる。
    4. 「処理用フォーム」というフォームを開いている。マクロのアクション「フォームを開く」と同じ処理を実行するための Docmd オブジェクトを使っている。3.での判断結果が「正」のとき、つまりオペレータがOKボタンを押した時だけ実行される。
    5.  3.での判断結果「誤り」の場合、という意味。オペレータが押したボタンがOKボタンでない場合(キャンセル、NOのどっちか)4.の処理をせずにこっちに制御が移る。
    6. もし、「Ret」の中身が「vbCancel」だったら、という判断をしている。つまり、前のMsgBox関数を実行したとき、オペレータが押したのがキャンセルボタンだったら、という意味。もしキャンセルボタンを押した場合、3.での判断結果が「誤り」となり制御が5.に移ってきて、6.の判断が実行される。
    7. MsgBox 関数を実行。オペレータにキャンセルしたことを確認通知するために、画面に「キャンセルしました」というメッセージを表示している。
    8. 6.のif文の終了。If文1つにつき1つ、必ずEnd Ifが必要になる。Elseは必要がなければ無くてもよい。
    9. 3.のif文の終了。
      どうでしょう?なんとなく、「処理の分岐」のイメージがつかめてきましたか?
      このように、If文を使えば、IIF関数ではできなかった複雑な判断ができるようになり、それだけ小回りのきく処理を行うことができるようになります。

      ここで注目してもらいたいのが「判断」「変数」です。
      「判断」の結果は、「正」「偽(誤り)」の2種類しかありません。(VBAではこれを True(正)False(偽)とあらわすことがありますので覚えておきましょう)
      では、分岐処理は2つにしか分岐できないのか?いいえ、そうではありません。
      この例のように、If文の中でさらにIf文を書くことができるので、判断結果が False だったとき別の判断をするようにすれば、いくつにでも分岐することができますね。もちろん、判断結果が True だったときにまったく別の判断をすることもできますから、And と Or が複雑にからみあう条件を指定するときなど便利です。

      ここで、なぜ「Ret」という変数を使ったのかというと、MsgBox関数の結果を保存しておきたいからなのですが、今回の場合は「NO」ボタンを押されたときに何もしていませんから、分岐は2つで済むので結果を保存しておく必要は、実はありませんでした。
      が、「NO」ボタンを押されたときに別のフォームを開く必要があったときどうでしょう。MsgBox 関数の結果を変数に代入しておかなければ、2つにしか分岐することができません。

      IF MsgBox(“処理していいですか?”,vbYesnoCancel) = vbOK then
      Docmd.OpenForm(“処理用フォーム”)
      ELSE
      MsgBox(“キャンセルしました”)
      End If

      結果を保存しないとすると、上記のようになるのですが(このページの下「関数の呼び出し方」参照)、この場合 Else に制御が移ったときには、もう MsgBox 関数の結果はどこかへ行ってしまっています。NOボタンなのかキャンセルボタンなのか判断しようとしてもできないのです。

      このように変数は、あとでもういちど使いたい値を保存しておいたり、数を数えたり、四則演算をしたり、別のモジュールに値を渡したりといろいろなことに使えます。
      変数には本体の EXE が終了するまで(Accessの場合はMSACCESS.EXEの終了 または mdb を閉じる)値が残っているものもあれば、定義したモジュールが終わってしまえばメモリ上から消えてなくなってしまうものもあります。(変数のスコープ と言います)
      用途によって使い分けましょう。

      変数に値を代入するには、= を使います。
      a = 1
      これで、「a」 という変数「1」という値が入りました。マクロの「値の代入」アクションよりも簡単ですね!
      上記の例では、MsbBox 関数が返してきた「どのボタンが押されたか」という情報を = を使って「Ret」に代入しているわけですね。こうすることにより、このモジュールの中ではいつでも MsgBox 関数の結果を見ることができるのです。

      *各関数の詳しい機能についてはHelpを参照してください

  • Docmdオブジェクトの使い方
    マクロは使ったことがありますか?フォームを開いたり、レポートを印刷したり。
    実は、VBAでもマクロは使います。正確にはマクロではなく、Docmd オブジェクトですが。
    フォームを開いたり、閉じたり、レポートを印刷したり、プレビューで開いたりといった動作は、VBA に対応する命令は用意されていないので、Docmd オブジェクトを利用して実行することになります。
    ただしVBAで利用するときには日本語名でアクションを指定できないので、(旧バージョンの Access ではできる場合があります)Helpを引いてVBA での記述を調べる必要があります。
    また、Docmd オブジェクトにはないアクションVBA に対応する命令があるアクションもありますので、Helpで確認しながら利用するようにしましょう。
    (値の代入アクションやメッセージの表示アクションは Docmd オブジェクトにはありません。また、フォーカスの移動アクションや再描画アクションはVBAに対応する命令が用意されているのでVBAの命令を使いましょう)

  • 実行中オブジェクトのコントロールの値の参照
    実行中オブジェクト、というとなんだかわらりづらいですが、要するにフォームレポートのことです(^^;)
    みなさんが VBA を記述するとしたら、おそらくフォームやレポートの「イベントプロシージャ」内でしょう。
    だとすると、「フォームのこの項目に入ってる値が見たい!」とか「いま印刷してるデータで計算したい!」ってことになってきますよね。
    この場合よく見掛けるのが、

    Forms![フォーム名]![コントロール名]

    という文法ですね。クエリーなどでフォームに入力された値で抽出処理したい場合など、この書き方を勉強したのではないでしょうか?
    イベントプロシージャに限ってですが、自分のフォームやレポートのコントロールの値を参照する場合には、フォーム名やレポート名を省略することもできます。

    Me![コントロール名]

    と書けば、自オブジェクト内のコントロールだと判断してくれますので、いちいちフォーム名やレポート名から書かなくても大丈夫です。ただし、レポートから表示中のフォームの値を参照、って時には自オブジェクトじゃないですから、フォーム名から書かないとだめですよ。
    では、一番よくある(と、思われる 実際はそんなのないかな・・・)パターン、レポートの詳細セクションに、「数量」と「単価」から、「金額」を計算して求める処理をやってみましょう。

    Private Sub 詳細_Format(Cancel As Integer, FormatCount As Integer)
    ‘詳細セクションのフォーマット時イベント

    Me![金額] = Me![数量] * Me![単価]

    End Sub

    [金額] は詳細セクション上の非連結コントロール、[数量]と[単価]は連結コントロールだとします。
    * は「掛け算を行う」という記号です。四則演算の記号についてはHelpで確認してください。

  • 関数の呼び出し方
    VBA 内でも関数はもちろん使えます。上記の例でも MsgBox 関数を使いましたよね。
    関数の呼び出し方にはいくつかの記述方法があります。DLookUp 関数で説明しましょう。
    • Me![名称] = DLookUp(“商品名”,”商品マスター”,”商品コード='” & me![商品コード]& “‘”)
      一番一般的な書き方ですね。DLookUp 関数の結果を、「名称」という名前のコントロールに代入しています。
      こうすれば、変数などを利用せずに直接「名称」というコントロールに商品名を表示することができます。
    • If IsNull(DLookUp(“商品名”,”商品マスター”,”商品コード='” & me![商品コード]& “‘”)) Then
      商品名をどこかで使うわけではないけど、関数の結果を一時的に判断したい時このようにIf文の中で呼んでしまうことがあります。この場合、判断処理が終わったら取得した名前は消えてしまいますから、商品名をどこかに表示する必要がでてきた時にはもう一度DLookUp関数を実行することになってしまいます。
    • Call DLookUp(“商品名”,”商品マスター”,”商品コード='” & me![商品コード]& “‘”)
      ただ呼ぶだけ、結果を保存も判断もなにもしない場合、先頭に「Call」をつけて呼び出すことができます。
      DLookUp関数ではまったくなんの意味もない呼び出し方ですが、自分で作った標準モジュール等を呼び出す場合、モジュール内で処理さえしてくれればいい、結果の判断は必要ない、という時にこのような書き方をすることもあります。

ここまで覚えれば、もう VBA は大丈夫。恐いことはありません。
Helpに載っている例だって、参考書のサンプルモジュールだって、以前とは比べ物にならないぐらい「見えてくる」はずです。
え? DAO の説明がない?だって、DAO と VBA は別物なんですよ。
DAO は、VB 等他言語からも使えるJetエンジンとのインターフェースです。SQL エンジンの特性、レコードセットの性質など覚える事柄も多く、習得は簡単ではありません。いきなり DAO を使おうと無理をするから、VBA への敷居が高くなってしまうんですよ。

・・・そうは言っても、「VBA を覚えたい」理由のダントツNO.1は「DAO、ADO を使いこなしたい」でしょう。(^^;)
ここで説明すると長くなりますので、また別の機会に・・・・