🦔

Excel VBAの基礎

に公開

マクロを動かしてみよう

Excelマクロ...というとどんなイメージでしょうか?
私は最初「なんか難しそう」と印象を持っていました。

しかし、1回動かしてみればわかりますが案外難しくありません。
百聞は一見に如かず、まずはマクロを動かしてみましょう。

VBE(プログラムを書くところ)を開く

Excelを開いたら、Alt + F11キーを押してみてください。

たぶんこんな感じの画面が開くと思います。


そしたら、左上にこんな部分があると思うので「Sheet1」をダブルクリックして


こんなのが表示されればOKです。
この部分に、Excelマクロに実行させたい内容を記述していくことになります。
この「プログラムを記述する部分」をVBEと呼びます。
※VBE:Visial Basic Editor

Hello Worldの表示

Option Explicit
Sub Hello_World()
    MsgBox "Hello World"
End Sub

次にVBEに上記コードを記入してください。
そのうえで2~4行目にカーソルを置いた状態でF5キー、または下図の▷をクリックするとプログラムが実行されます。

「Hello World」のメッセージボックスが表示されれば成功です。

ボタンにマクロを設定

図形でもいいのですが、ボタンにすると一気にマクロ感(?)が増します。

「開発」タブ>挿入
からボタンを選択して表に配置すると

図のように先ほど作成したHello Worldのマクロが選択できるようになっているのでこれを選択。
できたボタンをクリックすると...

こんな感じで作成したマクロを実行できるようになります。

「開発」タブがない...!?

そんな時は、「ファイル」タブをクリックして、画面下側の「オプション」をクリック

リボンのユーザー設定 から開発にチェックを入れてください

プログラム解説

Option Explicit

後述する「変数」を一度宣言してからじゃないと使えなくするという記述。
詳細は変数セクションで説明するとして、これがあるとタイピングミスによるバグを減らす効果がある。

Sub ~ End Sub

この範囲内を「1つのプログラムとする」という単位だと考えてもらえれば。
VBE内に1つだけにしなければならないという制限はなく、いくつ作成してもよい。
それぞれを図形やボタンなどに設定することができるので、

  • 「削除」ボタンには削除のプログラムを
  • 「更新」ボタンには更新のプログラムを
  • ...

のように設定することができる。

なお、Subの後の Hello_Worldは、このプログラムの名前を意味します。
その後の()は引数(後続で説明)を意味します。

MsgBox

MessageBoxの略で、読んで字のごとく「メッセージボックス」です。
1つだけ値を設定することで、今回のようにメッセージを表示できますし、
呼び出し方によってはOK・キャンセルを選択できるようになっているコマンドです。

Tips:VBEの設定

「ツール」タグの「オプション」

「エディターの設定」タブ

から、VBEの背景色や文字色を変更することができます。
私好みに変えるとこんな感じ。

  • 標準コード(前景:黄色/背景:黒)
  • コメント(前景:緑/背景:黒)
  • キーワード(前景:水色/背景:黒)
  • 識別子(前景:白/背景:黒)

デフォルトのままが見やすければ特に変更する必要はありません。
※個人的には背景黒にしたほうが「プログラムっぽい!」という理由で好きです。

セルの操作

セルの選択 -値の入力・取得-

特定のセルを選択して、値を入力したり取得したりすることができます。
案外これができるだけで、「あのルーティン作業効率化できるんじゃね?」が思いつくかもしれません。

まずはRangeを使ってA1セルを選択し、aを入力してみましょう

Sub A1()
    Range("A1").Value = "a"
End Sub

こっちは直感的にわかりやすいと思います。

同様にCellsを使ってA2セルを選択し、bを入力します。

Sub A2()
    Cells(2, 1).Value = "b"
End Sub

Rangeに比べるとわかりにくいかもですが、Cells({縦(行)}, {横(列)})でセルを選択する方法です。
学校で習ったXY座標の読み方と縦横が逆転してるのが最初は混乱するかも?ですが、まあ...慣れてください笑

最後に、Hello Worldの際にも使ったMsgBoxを使って、A2セルに入力された内容を表示してみましょう。

Sub MsgBox_A2()
    MsgBox Cells(2, 1).Value
End Sub

試しにご自分でも適当な内容をA2セルに入力して実行してみてください。
入力された内容が表示されるはずです。

.Valueって何もの?

そのセルのを入力、取得...というように「値」であることを示しています。
というのも、セルには

  • 背景色
  • 文字色
  • 文字サイズ
  • ...

などいろいろな設定事項があるので、そのうちの「値」を操作してるんだよということを明記しています。

おそらく今回くらいの内容であれば、.Valueの記載がなくとも動くかもしれませんが...
思わぬところで想定外の挙動をしないようにするためにも、「値」だよと明記する癖をつけておくことをオススメします。

ちなみに、こういう設定事項のことをプロパティと呼んだりします。

Sub test()
    Cells(2, 1).Interior.Color = vbRed
End Sub

例えばこれなら、A2セルの背景色を赤に設定します。

変数とは?

プログラムの中で「値を入れておく箱」のようなもの。
計算した結果や文字を一時的に保存して使い回すことができる。

これがあると例えば、

  • セルの入力内容に応じて処理を変える
  • 計算途中の値を記録しておく
    みたいなことができるようになります。
Sub Sample_Variable()
    Dim number As Integer ' 整数を入れる変数
    Dim name As String    ' 文字を入れる変数

    number = 10
    name = "田中さん"

    MsgBox name & "の点数は" & number & "点です。"
End Sub

変数の利用イメージとしてはこんな感じ。
Dimというコマンドの後に変数名を設定、その後にその変数はどういうデータ型なのか?を宣言します。
データ型、とは

  • 整数
  • 文字列
  • 時間
    など様々なものが存在します。
    例えば、整数型の1と整数型の2を+で計算すると、1+2=3となります。
    1と2を文字列とした場合は、1+2=12となります。
Sub Sample_Variable()
    Dim one As Integer
    Dim two As Integer
    one = 1
    two = 2
    MsgBox (one + two) ' 3が表示される
    
    Dim o As String
    Dim t As String
    o = "1"
    t = "2"
    
    MsgBox (o + t)  '12が表示される
End Sub

Option Explicitについて

これがあると、上述のようにDim ... As ... で宣言していない変数は使えなくなります。
逆に、書かなければわざわざ宣言せずとも使えちゃいます。

Sub Sample_Variable()
    one = 1
    MsgBox one ' Option Explicitがなければ実行できる
End Sub

え、じゃあいらなくね?となるかもしれませんが、これがあるとタイピングミスによる影響を低減することが期待できます。

Sub Sample_Variable()
    one = 1
    two = 2
    
    MsgBox (one + tow)
End Sub

これをこのままコピーして実行すると、1が表示されるはずです。
...そうです、towという変数はMsgBoxの中が初出なので実質何も入っていないことが原因です。

これが業務で使っているExcelで入力がすべて間違っていたり、中途半端なところまで入力されたうえでエラーになったりしたら...
考えるだけでぞっとしますね...

Option Explicitがあると、towなんて変数宣言されてないよと実行前にエラーを表示してくれます。
間違った内容を実行する・中途半端な状態まで実行するよりは、最初から止めてくれたほうがダメージが少ないことが多いので、おまじないだと思って毎回入力することを推奨します。

「ツール」タブ>オプション
から「変数の宣言を強制する」にチェックを入れておくと、毎回入力する必要もなくなるので、こだわりがなければチェックを入れておきましょう。

条件分岐

「もし○○なら~する、そうでなければ~する」という処理。

Sub Sample_If()
    Dim score As Integer
    score = 65

    If score >= 70 Then
        MsgBox "優秀です!"
    ElseIf score >= 60 Then
        MsgBox "合格です!"
    Else
        MsgBox "落第!"
    End If
End Sub

If (条件) Then
(処理内容)
End If
という形で、条件が満たされたときのみ処理を実行するというコードになります。

ElseIfは、2つ目・3つ目...の条件を設定でき、Elseは「それ以外」を示しています。
1点注意として、先に設定された条件を優先することを覚えておいてください。

Sub Sample_If()
    Dim score As Integer
    score = 75

    If score >= 60 Then
        MsgBox "合格です!"
    ElseIf score >= 70 Then
        MsgBox "優秀です!"
    Else
        MsgBox "落第!"
    End If
End Sub

これだと、「合格です!」が表示されます。
scoreが75なのに、「優秀です!」が表示されないのは、先にscore>=60の条件を満たしてしまうので、そっちの処理が優先されていることが原因です。

条件設定のミスはあるあるなので、順番には十分に注意してコードを作成したいですね。

繰り返し処理

Forを使った繰り返し

Sub TestFor()
    Dim i As Integer
    For i = 1 To 10
        Cells(i, 1).Value = i
    Next i
End Sub

こんな感じで
For (変数) = (開始の数値) To (終了の数値)
(具体的な処理)
Next (変数)
によって、開始から終了まで1ずつ増加しながら同じ処理を繰り返すことができます。

サンプルコードを動かすと
Cells(1, 1) ※A1 に1
Cells(2, 1) ※A2 に2
...
Cells(10, 1) ※A10 に10
を入力する動きになります。

Whileを使った繰り返し

Sub TestWhile()
    Dim i As Integer
    i = 1
    Do While i <= 10
        Cells(i, 1).Value = i
        
        i = i + 1
    Loop
End Sub

こんな感じで
Do While (条件)
(具体的な処理)
Loop

とすることで、条件を満たす間処理を繰り返すというコードになります。
※実行結果はForのサンプルと一緒です。

Tips:無限ループに注意!

Sub TestWhile()
    Dim i As Integer
    i = 1
    Do While i <= 10
        Cells(i, 1).Value = i
    Loop
End Sub

※このコードは実行しないでください

さて、先ほどのWhileループの一部を書き換えております。
i = i + 1
の処理が抜けていますね。
これを実行するとどうなるか?

  • 1回目:i = 1でi <= 10 なのでCells(1, 1).Value = 1 を実行する
  • 2回目:i = 1でi <= 10 なのでCells(1, 1).Value = 1 を実行する
  • 3回目:i = 1でi <= 10 なのでCells(1, 1).Value = 1 を実行する
  • ...

はい、いくら待っても処理が終わらない無限ループになります。

で、VBAの実行中ってこちらからのExcel操作を受けつかなかったりするのでこうなっちゃうと無理やりExcelを終了するしかなくなったりします。(n敗目)

無限ループにならないように十分注意する、というのも大事ですが、ループの中にDoEventsコマンドを入れておくことを推奨します。

Sub TestWhile()
    Dim i As Integer
    i = 1
    Do While i <= 10
        Cells(i, 1).Value = i
        
        ' 一瞬Excelに制御を返す
        DoEvents
    Loop
End Sub

これで処理の途中で一瞬制御がVBAから画面操作に帰ってきます。
すると、その帰ってきた瞬間にはマクロの停止(Escキー)を受け付けるようになるので、Esc長押しでマクロを強制終了できるようになります。

実際には毎回DoEventsを呼ぶと処理が重くなってしまうので、10回に1回だけ呼ぶようにするなどでよいと思います。
...え、「10回に1回」の制御に失敗したら?...まあ、Excelの強制終了で、何とか...

Function

さて、これまですべてのマクロはSub ~ End Subの中に全処理を記述してきました。
しかし、処理が難しくなってくると全部書くととんでもないコード量になることも多いです。
また、同じような処理を何回もやっている場合、それを何か所にも記述するのは無駄も多いし、何より修正する場合に全部の修正が必要になって大変面倒です。
大体1,2個修正しそびれてバグを起こします

そこで、特定の処理だけ別の場所に記述しておける方法としてFunctionがあります。
関数とかメソッド、という呼び方もあり、Functionを実行することを呼ぶと言ったりします。

Option Explicit

Sub TestFunc()
    Dim i As Integer
    Dim result As String
    
    i = 3
    result = judge(i)
    MsgBox result
End Sub

Function judge(i As Integer) As String
    Dim ret As String
    If i Mod 2 = 0 Then
        ret = "偶数です"
    Else
        ret = "奇数です"
    End If
    
    ' 返却
    judge = ret
End Function

TestFuncのコードを実行すると、iの数値に応じて「奇数です」「偶数です」が表示されます。

judge (i As Integer) As String
ここは、Functionに渡す引数を設定します。
ExcelのSum関数で例えると
Sum(A1:A10)
という書き方をすると、A1~A10の合計を計算して、という処理になりますよね?
このA1~A10にあたるものを引数と言います。
judgeは整数1つを引数に設定できる関数ということですね。

judge (i As Integer) As String
これは戻り値・返り値と呼び、実行した結果何を返却するか?を表しています。
※正確には戻り値はjudgeであり、As Stringはjudgeのデータ型ですが...そんなもんか、で聞いてください

Sum関数であれば、合計した数値が計算結果として戻ってきますよね?
そんな感じで、judgeは処理の結果を文字列で返すという意味になります。

配列

複数のデータを1つの変数に格納することができ、そういった変数を配列と言います。
社員複数人がいるときに、1人1人変数を用意せずとも1つの変数にまとめて処理することが可能です。

Sub TestArray()
    Dim myArray As Variant
    ReDim myArray(1 To 3)
    
    myArray(1) = "佐藤さん"
    myArray(2) = "伊藤さん"
    myArray(3) = "田中さん"
    
    Dim i As Integer
    For i = LBound(myArray, 1) To UBound(myArray, 1)
        Cells(i, 1) = myArray(i)
    Next i
End Sub

※LBound:配列の開始値を抽出 UBound:配列の終了値を抽出

多次元配列

配列は下記のように次元を2つ以上持つことができます。

Sub TestArray()
    Dim myArray As Variant
    ReDim myArray(1 To 3, 1 To 2)
    
    myArray(1, 1) = "佐藤さん"
    myArray(2, 1) = "伊藤さん"
    myArray(3, 1) = "田中さん"
    
    myArray(1, 2) = 80
    myArray(2, 2) = 75
    myArray(3, 2) = 90
    
    Dim i, j As Integer
    For i = LBound(myArray, 1) To UBound(myArray, 1)
        For j = LBound(myArray, 2) To UBound(myArray, 2)
            Cells(i, j) = myArray(i, j)
        Next j
    Next i
End Sub

2次元配列...というととっつきづらいイメージがあるかもですが、上のサンプルコードを実行すると下記のように表に書き込まれます。

見ての通り、「行・列」の2つを持つ配列だと思ってもらえればわかりやすいかなと思います。

セルと配列

2次元配列が行・列のデータだとすれば、セルのデータをまとめて2次元配列に格納することもできます。

こんな入力がされているとして、これを配列に格納するには

Sub TestArray()
    Dim myArray As Variant
    myArray = Range("A1:B3").Value
    
    Dim i, j As Integer
    i = 2
    j = 1
    
    MsgBox i & "行" & j & "列目の値は" & myArray(i, j) & "です"
End Sub

と、範囲をまとめて配列に代入することができます。

何度も何度もセルにアクセスするより、1度でまとめて配列に入れてしまったほうが記述も簡単だし処理も早いしなので、ぜひ使えるようになっておきたいですね。

マクロとChatGPT

ChatGPTじゃなくCoPilotでもGeminiでもいいですが、「あとはコード書くだけ!」まで落とし込めると生成AIはものすごい効力を発揮します。

ここまでの内容でマクロ実行のイメージはついてきているかなと思うので、後は各自のルーティン業務をマクロに落とし込んでいけば、「マクロで業務効率化」ですね!

マクロの練習

具体的に作りたいものがパッと浮かばない...という人はVBA100本ノックという練習問題をまとめてくれているところがあるので使ってみるといいと思います。

VBA100本ノック


正直100本目までやりきる必要はないと思います。
私も最後まではやってません

コラム:情報システム部から見たExcelマクロ

業務効率化の強力なツールになってくれるExcelマクロですが、これが部署全体に広がってたりすると...まあ管理が大変です...

こういうIT管理者が把握していないITツールをシャドーITって言ったりするんですが...

  • マクロに任せて自分が何をやっているかわからない担当者
  • 会社の基幹システムにアクセスしているツールになってて、不要になったはずの画面・機能を基幹システムから削ぎ落したときにマクロが動かなくなる&なんで動かないかわからなくてパニック
  • マクロの作成者が異動or転職して
  • ...

まあとにかく厄介者だったりします。
なのでExcelマクロは個人業務の効率化にとどめておいて、部署全体の効率化を行いたいなら会社のIT部門と相談してほしいなーというのが正直なところだったり。
そこまでするか?と言われると面倒だけど
そもそもマクロが使えるって周りにばれると変なタスクが降ってきたり

何やってるマクロかはわかりません。でも動かないと困るんです!作成者は転職しました。何ならマクロにパスワードがかかっていてコードが分かりません
勘弁して~

Discussion