VBA(マクロ)やってみよう ~コードの書き方~
事務仕事をされる方であれば、Excelは触らない日はないのではないでしょうか。僕は独学でPythonを学びましたが、そもそも会社でPythonを使える環境はないので、VBAも独学で勉強して色々試してます。
なんとなくは分かるけど、そもそもどうやって使えばいいのさ?という方が殆どだと思ので、まずは書き方と簡単な実例を解説します。
1.どうやってコードを書けばいいのか
まず、Excelを立ち上げましょう。そして、開発タブのVisual Basicからを選択します。(Alt+F11 または Alt+L+Vのショートカットでも立ち上がります)
こんな画面が開くと思います。
挿入から標準モジュールを選択します。(Alt + I + MのショートカットでもOK)
こんな画面が開きます。基本的にはここに、プロシージャというプログラムを書いていきます。なお、プロシージャは基本的にエクセルファイル内の処理を自動化するプログラムです。Pythonの関数のように、引数をとって何らかの値を返したりするものはファンクションといい、VBAでは区別されています。
2.書き出しと締めくくり
書き出しと終わりは必ず、「Sub プロシージャ名()」ではじまり「End Sub」で締めくくります。
以下のように記載します。
Sub プロシージャ名()
(プログラムを記述)
End Sub
こんな感じです。なお、プロシージャ名は日本語でも英語でもOKです。
(休日判定、完了判定、8割算出等の日本語も大丈夫です)
3.変数の定義
プログラミンで特に押さえるべきポイントとして、以下記事でも触れました。
変数を定義することで、コード記述を簡単にしたり、保守性を向上させたりと様々なメリットがあります。
見た方がイメージしやすいと思うので、例えばセルに入力されている日付が今日よりも過去日なのか、それとも今日以降なのかを判定して、判定結果を表示させるプログラムを書いてみます。(進捗管理などに使えそうですね)
進捗表はこちらだったとします。(GWも仕事という・・・悲しい会社ですね)
どんな処理にすればいいかを考えます。
ポイントは、2行目からタスクが入ってる7行目まで、C列の期限が当日日付と比較して、過去日なら「遅延」、当日なら「当日期限」、未来日なら「オンスケ」とD列に表示するプログラムかなあと考えます。
これを実現するために、以下の流れで組み立てていきます。
➀ 今日の日付を取得し、変数todayに格納
➁ タスクが記述されている最終行を取得し、変数lastRowに格納
③ 2行目からlastRow行まで、ループ処理でC列日付をtodayと比較し、
比較結果をD列に入力
こんな流れですね。(もちろんこれが正解という訳ではないです)
では、これをコードとして書いていくと、、、こんな感じになります。
Sub アラート()
Dim ons, des, tos As String
Dim today As Date
Dim lastRow As Integer
Dim i As Long
today = Date
ons = "オンスケ"
des = "遅延"
tos = "本日期限"
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow
If Cells(i, 3).Value > today Then
Cells(i, 4).Value = ons
ElseIf Cells(i, 3).Value = today Then
Cells(i, 4).Value = tos
Else
Cells(i, 4).Value = des
End If
Next
End Sub
VBAでは、変数定義を頭でまとめて書きます。定義の仕方としては「Dim 変数名 As データ型」として記載します。
なおDimとは、Dimension(寸法・容積)の略で、リスト型の宣言に用いられていたものが、今日ではその他変数も含めて宣言に用いられているのではないかと以下記事に書いてありました(受け売り)
Asは「~として」という意味ですね。プログラミング学習をしていると、英語も覚えるという一石二鳥な効果が実はあります。これほんと。
では、今回のプログラムで定義している変数を見てみましょう。
Dim ons, des, tos As String
これは最終的に、D列に表示する進捗状況をあらわす文字列を格納するための変数です。変数onsに「オンスケ」、変数desに「遅延」、変数tosに「当日期限」をそれぞれ格納するため、文字列型の変数だよということを宣言してます。文字列型はStringです。
Dim today As Date
これは、C列の期限と比較を行うために、変数todayに今日の日付を格納するための宣言です。日付型はDateと記載します。
Dim lastRow As Integer
これは、タスクが記載されている最終行の行番号を変数lastRowに格納するための宣言です。なお、数値型について、Pythonでも整数と浮動小数でデータ型が異なりますが、VBAではもっと細かく分かれています。整数値で、32,676以下の数値を扱うのであればIntegerで事足ります。Longはもっと大きな数を扱え、Single・Doubleで小数を扱えます。
以下の記事がとても分かりやすいので、ご参考に。
最後に、変数iを宣言しているのはループ処理で2行目から、最終行目まで同一処理を繰り返す際に、iに2~7を格納していくためのものです。前述のとおり、少なくとも32,767以下なら、IntegerでもOKです。
4.最終行の取得の仕方
タスク列に入力されている分、期日判定をしたいのでどこの行まで入力されているかを動的に確認する必要があります。
毎回、最終行を確認してコードを書きなおしていては「自動処理」とは言えないですね・・・。そんな時はこう書きます。
Cells(Rows.Count, 1).End(xlUp)
Cells(x, y)という書き方はRange型といって、セルの範囲等を指定するのに使います。これを見慣れたセル名で表記する場合は、Range("A1")(A1セル)や、Range("A1:C3")(A1セルからC3セルまでの範囲を指定)のようになります。動的にセルを指定する場合は、Cells(x, y)という書き方のほうが便利なので私はそうしています。
xが行数(Row)、yが列数(Column)を表します。Rows.Countはエクセルシート自体の最終行を示しています。(1,048,576行目)
列数は1なので、最終行までいってから、値が入ってるセルを.End(xlUp)で上方向に探しにいっています。
つまり、以下のような動きです。
A1セルからエクセル操作で言うと、Ctrl + ↓ キーを2回押して、Excel自体の最終行へ、そのあとCtrl + ↑キーで7行目にたどり着く感じですね。
もちろん、以下の書き方も不正解ではないです。
Cells(1, 1).End(xlDown)
ただ、例えば8行目がブランクで9行目にまた値がある、などといった場合この書き方だと9行目は拾い漏れます。そのため、このように書いています。
また、最後に.Rowとすることで行番号を数値で取得できます。.Rowをつけない場合、セル自体の値を取得することになるのでご注意ください。僕は良く忘れてエラーになります 笑
なお、VBAでは「MsgBox」でポッポアウト出力させることが可能です。以下を試すと、7行目に入力されている”□□案件の見積書説明”というセルの値が出力されます。
MsgBox Cells(1, 1).End(xlDown)
一方、以下コードを書くと、行数である7が出力されます。
MsgBox Cells(1,1).End(xlDown).Row
後は、これを数値型として宣言した変数lastRowに格納してしまえば、以降上のながーいコードを書かずにlastRowだけで流用できるのです。
僕のVBA歴はかなり浅いですが、今まで作ったプログラムでこの最終行取得を使わないケースの方が珍しいくらい、良く使います。
暗記する必要はなくて、「なんか書き方あったよな」と知っておけばOKです。(後でいくらでも細かい書き方は調べられます)
5. 繰り返し(ループ)処理の書き方
では、2行目から取得した最終行まで同じ処理を繰り返すためのループ処理の書き方を見ていきましょう。Pythonの記事を読んでいただいている方は、すでに大体概要は理解されていると思いますが、VBAはこうやって書くんだね~くらいに、これも知るだけで大丈夫です。(暗記の必要なし)
VBAにもリスト型のようなものはあり、リストに対するループ処理の書き方やWhileループもありますが、頻度としてはこのForループを書くケースが僕は多いです。書き方としては以下のとおり。
For ループ変数 = スタート値 To ゴール値
(処理)
Next
これだけです。今回は、あらかじめループ変数としてiを数値型(IntegerでもLongでもOK)として宣言。
スタート値として、値が格納されている2行目から先ほど取得した最終行の行番号を設定してます。
For i = 2 To lastRow
仮に、変数に最終行を格納してない場合は、、、
For i = 2 To Cells(Rows.Count, 1).End(xlUp).Row
となります。今回は1回ですが、このような処理を複数記載することが常なので、変数に格納しておくと便利ですっていう話です。
そして、繰り返したい処理を書いたら、「Next」で締めくくると、ForとNextの間の処理を指定したスタート値からゴール値の回数分繰り返してくれます。
6. 条件式(IF文)の書き方
こちらも、プログラミングをするうえで良く使います。
VBAでは、以下の書き方となります。
If 条件式➀ Then
(処理1)
ElseIf 条件式➁ Then
(処理2)
Else
(処理3)
End If
という書き方です。簡単に説明すると、もし条件式➀に合致する(=True)なら、処理1をしてね。条件式➁に合致するなら、処理2をしてね。条件式➀にも条件式➁にも合致しない(=False)場合は、処理3をしてね、となります。Thenを忘れがちですが、Thenは「その後」という意味の英語なので~なら、「その後」~するということです。(Pythonはいらないですね)
なお、条件が1つしかない場合は、IfとElseだけでいいですし、Elseは条件に合致しない場合の処理を書く場合に必要になるので、その処理もいらない場合は、Ifだけでも成立します。
また、3つ以上条件がある場合は、ElesIfは複数記述可能ですが、VBAにはCase文というのもあって、どちらで書くべきかは僕も良く分かりません(てへ)
あと、最後は「End If」で締めくくる必要があるので、これも忘れずに書いてください。暗記する必要はないですが。
7. 動かしてみよう
では、実際に書き上げたコードを動かしてみましょう。その場合にも、知っておくべきことがいくつかあります。
まず、コード実行はF5でできます。(▶ボタンか、実行→▶ボタンでもOK)
まずは動かしてみましょう。表とマクロを記載したファイルを置いておくので、まずは内容を見たいという方はダウンロードいただいても結構です。
ダウンロードした方は、ファイルを開いてAlt+F11か、Alt+L+VでVBAを起動してください。
こんな感じで、ウインドウ並べて、開けたらF5を押してみてください。
すると、進捗欄に文字が入力されたと思います。(記事記載時は4/11なので、実際に動かす日にちに合わせて、Excel側のC列期限をご自身で調整ください。)
8. 何が行われているかを確認する(デバッグ・ステップイン)
F5だと、一気に処理が完了しますが、VBAには便利なステップインという機能があり、一行一行コードを実行していくことができます。F8を押すか、デバッグ→ステップインで実行できます。
一行ずつF8を押していってみてください。そうすると、右下のローカル欄に何やら変数名が表示されたことに気付かれると思います。
ここで、1行ずつF8を押していくことで、変数に何が格納されたかを確認することができるのです。例えば、lastRowの行まで実行すると・・・
ons,des,tosにはそれぞれ、文字列が可能されています。また、lastRowには想定通り最終行である7が格納されました。lastRowの行も実行しているので、今表示されているのは、For i ・・・の行だと思います。
ここはまだプログラム実行されていないので、変数iは0のままです。
ここで更にF8を押すと・・・
変数iにスタート値である2が格納されたのが分かります。あとは、バーっとF8を押していくと、ループ処理が一周するごとに、iが1ずつ加算されていくのが分かると思います。
これにより、参照するセルがCells(2, 3)・・・C列2行目(=C2セル)、Cells(3, 3)・・・C列3行目(=C3セル)と、ゴール値であるCells(7, 3)・・・C列7行目(=C7セル)まで参照して、条件式で判定し、その後4列目(D列)に判定結果に応じて、あらかじめons、des、tos変数に格納された値をセットしているのが分かります。
8. ステップインの使い方
なぜ、このステップイン機能を説明したかというと、、、自分で実際にプログラムを書いていみると、上手くいかないことが殆どです。笑
ひたすら、エラーが出ます 笑
そんな時は、このF8でどう動いているのかを、見ることで一個一個エラー原因を潰すことができます。
まずは、全部一気に書こうとせず、パーツパーツで書いて、上手くいったら次のパーツといった感じで「小さく作っていく」のがコツです。
いきなり全部書いて、どっさりエラーがあると、心もくじけるので・・・
9. どんなプログラムを作ればいいのか
これも多くの場合、プログラムを覚えたての人がぶち当たる課題だと思います。僕もそうでした。お作法と、大体の書き方は分かったし、他の人が書いたプログラムを真似して動かしてみるのはできるようになったんだけど・・・
そもそも何を作ったらいいんだっけ???
そんな時は、身の回りで自動化したら便利そうなものを探してみてください。そして、その処理をするために、どんな工程(パーツ)が必要かを考えてみるのです。
あとは、そのパーツごとに少しずつ作りあげていく・・・というのが流れです。
10. 僕が一番初めに作ったプログラム
僕がVBAを覚えて、一番初めに作ったのは、会社のWeb勤怠システムの日々の勤務時間を8割に算出し直すというプログラムでした。
特定部署の勤務時間の8割を必要経費として、算出する必要があり、これを毎月集計する必要があるのです。勤怠システムはWebアプリケーションなのですが、これをブラウザで見ながら、数式が入力されたエクセルシートに日々の勤務時間を入力し計算した結果を、入力用のエクセルファイルに入れていく、この作業をみんな月初にしていました。
明らかに無駄な作業だなと思っていたので、Web勤怠システムのブラウザから、前月の勤怠実績をコピー&ペーストでマクロ機能があるエクセルに貼り付け、後はボタンをおしたら全日分8割計算を自動で行い、縦横変換して入力用ファイルにそのままコピペできるようにしたらどうかな・・・?
と思いついたのがきっかけです。あとは、ひたすら本記事でも記載した最終行の取得の仕方や、時間計算の仕方等は都度Googleで検索して、少しずつプログラムをくみ上げていった感じです。
この記事で解説した内容を知っていれば、大体のことはできると思います!
また、気が向いたら違うプログラムも紹介するので、是非、ご自身で色々試してみて下さい!
それでは、最後まで読んでいただきありがとうございました!!