こんにちは。ECF Tech担当
Michiharu.Tです。
Excel VBA トレーニング問題 No.2と致しまして、本ブログで提供しているExcel VBA入門 第11回までの内容を活用した練習問題をご用意致しました。Excel VBA初学者の方でも取り組める問題から実践に近い応用問題までをご用意しております。ぜひ、普段の学習にご活用頂ければと思います。
その他のExcel VBA関連の教材および練習問題は下記よりご覧いただけます。

使い方
- トレーニング用データをこちらよりダウンロードしてください。
- 各問題はダウンロードデータの初期状態から取り組むことを前提としています。
- 各問題は次の要素から構成されています。
- 問題:プログラムの作成指示です。
- 条件:プログラムを作成するにあたり、守るべき条件です。
- ヒント:プログラムを書くためのヒントです。
- 解答例:動作するプログラムの例です。
問題1
問題
B2セルとD2セルの内容を文字列として結合し、メッセージボックスに表示するマクロを作成してください。マクロ名はstringConcatとします。
処理イメージ
条件
- 「関数の動作」シートが対象です。
- 「関数の動作」シートがアクティブシートであることを前提に作成して構いません。
ヒント
文字列同士の結合には&
を使用します。
問題2
問題
2つの文字列を引数として受け取り、その文字列が示すセルの内容を結合した文字列を戻り値として返すFunctionプロシージャStringConat2を作成してください。
処理イメージ
次のマクロを実行して動作を確認します。
Sub ShowNewMenu() Range("B8").Value = StringConcat2("B5", "C6") End Sub
実行結果は次のようになります。
B5セルとC6セルの内容を結合したものが、B8セルに表示されています。
条件
- 「関数の動作」シートが対象です。
- 「関数の動作」シートがアクティブシートであることを前提に作成して構いません。
ヒント
戻り値を返すプロシージャを作成する場合は、Functionキーワードを使います。該当の講座ページはこちらです。
問題3
問題
問題2で作成したStringConat2プロシージャを呼び出して、次の処理を行うマクロを作成してください。マクロ名はshowNewMenu2とします。
- C5セルとD6セルの内容を結合し、B9セルに設定
- D5セルとE6セルの内容を結合し、B10セルに設定
- E5セルとB6セルの内容を結合し、B11セルに設定
処理イメージ
条件
- 「関数の動作」シートが対象です。
- 「関数の動作」シートがアクティブシートであることを前提に作成して構いません。
ヒント
問題2の動作確認用マクロとほぼ同じ記述となります。
問題4
問題
C14~C16セルに、今日、明日、明後日の日付を入れるマクロを作成してください。マクロ名はthreeDaysとします。
処理イメージ
2025年8月9日に実行した場合の表示は、つぎのようになります。
ヒント
DateAdd関数を使用します。該当の講座ページはこちらです。
問題5
問題
(1)次の仕様で動作するプロシージャsetNumbersを作成してください。
- 行番号(row)と列番号(col)を引数にとります。
- row行col列目のセルを左端とした右方向5つ分のセルに1~5までの値を設定します。
(2)下の処理を実行するマクロを作成してください。マクロ名はshow5とします。
- (1)で作成したプロシージャを呼び出し、B19セルを左端として1~5までの値を表示してください。
- (1)で作成したプロシージャを呼び出し、D21セルを左端として1~5までの値を表示してください。
処理イメージ
条件
- 「関数の動作」シートが対象です。
- 「関数の動作」シートがアクティブシートであることを前提に作成して構いません。
ヒント
Call Subプロシージャ名
でSubプロシージャを呼び出せます。
問題6
問題
日付1(B25)セルと日付2(C25)セルの日数差をE25セルに求めるマクロを作成してください。マクロ名はshowIntervalとします。日付1または日付2に日付とみなせる値が入力されていない場合は、処理イメージに示すようにメッセージボックスを表示してください。
処理イメージ
日付1の値が不正の場合
日付2の値が不正の場合
正常動作
条件
- 「関数の動作」シートが対象です。
- 「関数の動作」シートがアクティブシートであることを前提に作成して構いません。
ヒント
- 日付形式のチェックにはIsDate関数を使います。
- 日数差を求めるにはDateDiff関数を使います。
問題7
問題7以降はすべて「勤怠表」シートを使用します。「勤怠表」シートにはあらかじめ次の設定がされています。
- 日付列:日付書式になっています。
- 曜日列:日付から曜日を求める計算式が入っています。
- 開始時刻列,終了時刻列:時刻書式になっています。
上記の設定を削除してしまった場合、練習問題が正しく動作しない可能性があります。その場合は、「勤怠表(予備)」シートをコピーして「勤怠表」シートという名前に修正して、復元することができます。
問題
開始時刻列、終了時刻列の空欄をチェックし、空欄の場合は背景色を黄色にするマクロを作成してください。マクロ名はcheckEmptyとします。
処理イメージ
条件
- 「勤怠表」シートがアクティブシートであることを前提に作成して構いません。
ヒント
- 空欄判定はIsEmpty関数で行うことができます。
- For文とCellsによるセル参照を活用して組み立ててみましょう。
問題8
問題
勤怠表内の各行について、開始時刻と終了時刻から勤務時間を求め、勤務時間列に表示するマクロを作成してください。マクロ名はcalcWorkTimeとします。
処理イメージ
- 開始時刻が9:00、終了時刻が18:00の場合は9時間勤務です(図①)。
- 開始時刻が9:00、終了時刻が12:00の場合は3時間勤務です(図②)。
- 開始時刻または終了時刻のいずれかが空欄なら、勤務時間の計算は行われません(図③)。
条件
- 「勤怠表」シートがアクティブシートであることを前提に作成して構いません。
- 開始時刻列および終了時刻列について、時刻とみなせない値が入力されることはないものとします。空欄の可能性のみを考慮すればOKです。
ヒント
勤務時間の求め方
DateDiff関数を活用しましょう。DateDiff関数の第1引数は指定する値によって差を求める単位を変えることができます。指定できる値の一部を下に示します。
指定値 | 意味 |
---|---|
d | 日単位 |
h | 時単位 |
n | 分単位 |
プログラム構成
For文を使って、1行ずつ処理を行いましょう。
問題9
問題
B2セルに西暦年、D2セルに月を入力して実行すると、表の日付列に1ヶ月分の日付を入力するマクロを作成してください。マクロ名はinsertMonthDateとします。年(B2セル)または月(D2セル)に数値とみなせる値が入力されていない場合は、処理イメージに示すようにメッセージボックスを表示してください。
処理イメージ
西暦年の入力不正の場合
月の入力不正の場合
正常動作
日付列に1ヶ月分の日付が入力されます。6月なら30日分、7月なら31日分の日付が設定されます。
曜日列は計算式が入っているため同時に自動で表示されます。
条件
- 「勤怠表」シートがアクティブシートであることを前提に作成して構いません。
- 曜日列についてのプログラムは記述不要です。
ヒント
日数の求め方
指定年月の日数を求める方法は少々複雑です。手順は次のようになります。
- 翌月1日にあたる日付情報(翌月初日情報)を取得(DateSerial関数を使用)。
- 翌月初日情報から1日引き算し、指定年月の末日の日付情報(該当月末日情報)を取得(DateAdd関数を使用)。
- 該当月末日情報から日付を数値として取得する(Day関数を使用)。
指定範囲セルのクリア
次の記述で日付列をクリアできます。日付表示の前に実行しておくと、きれいに表示できます。
Range("A5:A35").ClearContents
問題10
問題
問題7で作成したマクロcheckEmptyを改良したマクロを作成します。マクロ名はcheckEmptyWeekDayとします。checkEmptyWeekDayでは、開始時刻列と終了時刻列について平日(土日以外)についてのみ空欄チェックを行い、空欄の場合に背景色を黄色にします。
処理イメージ
条件
- 「勤怠表」シートがアクティブシートであることを前提に作成して構いません。
- 日付列および曜日列について、正しく入力されている前提で作成して構いません。
[PR]
Excel VBAの実力を認定するVBAエキスパート試験の対策本です。

問題1 解答例
Sub stringConcat() MsgBox Range("B2").Value & Range("D2").Value End Sub
解説
&
を使って、B2セルの値とD2セルの値を結合しています。
問題2 解答例
Function StringConcat2(cell1 As String, cell2 As String) As String StringConcat2 = Range(cell1).Value & Range(cell2).Value End Function
解説
引数cell1
、cell2
の文字列はセル位置を表現する文字列として使用するため、Range(cell1).Value
のように使用しています。
問題3 解答例
Sub showNewMenu2() Range("B9").Value = StringConcat2("C5", "D6") Range("B10").Value = StringConcat2("D5", "E6") Range("B11").Value = StringConcat2("E5", "B6") End Sub
解説
問題2で作成したStringConcat2を呼び出しています。StringConcat2は戻り値を返すため、Range("B9").Value =
のように記述して戻り値をセルに代入しています。
問題4 解答例
Sub threeDays() Range("C14").Value = Date Range("C15").Value = DateAdd("d", 1, Date) Range("C16").Value = DateAdd("d", 2, Date) End Sub
解説
- 本日日付はDate関数を使って取得しています。
- 翌日日付はDateAdd関数を使って、本日日付(
Date
)に1日加算することで取得しています。DateAdd関数の第1引数は加算単位で"d"
が指定された場合は日単位です。したがって、第2引数が1
の場合は1日加算。第2引数が2
の場合は2日加算されます。第3引数は加算対象となる日付情報です。
問題5 解答例
(1)
Sub setNumbers(row As Integer, col As Integer) Dim i As Integer For i = 0 To 4 Step 1 Cells(row, col + i).Value = i + 1 Next End Sub
(2)
Sub show5() Call setNumbers(19, 2) Call setNumbers(21, 4) End Sub
解説
- setNumbersは行番号と列番号の2つを引数に持つ必要があるため、
row As Integer, col As Integer
としています。 - For文は変数iを0~4まで1ずつ変化させながら、5回くり返します。
- Cellsプロパティは行番号と列番号の2つを引数に取ります。
col + i
のように列番号にiを加算することで、ループのたびに対象セルを右にずらしています。
問題6 解答例
Sub showInterval() '日付1のチェック If Not IsDate(Range("B25").Value) Then MsgBox "日付1に日付を入力してください" Exit Sub End If '日付2のチェック If Not IsDate(Range("C25").Value) Then MsgBox "日付2に日付を入力してください" Exit Sub End If Dim day1 As Date Dim day2 As Date day1 = CDate(Range("B25").Value) day2 = CDate(Range("C25").Value) '日数差を求める Range("E25").Value = DateDiff("d", day1, day2) & "日" End Sub
解説
- IsDate関数でセルの値が日付形式になっているかどうかをチェックしています。
- IsDate関数は引数の値が日付形式であればTrueとなります。日付をチェックするIf文は日付形式でない場合にTrueとしたいため、IsDateの呼び出しの前に
Not
をつけて、判定結果を反転(TrueならFalse,FalseならTrue)させています。 - CDate関数を使って、各セルの値を日付型として変数day1、day2に取得しています。
- DateDiff関数で、day1とday2の日数差を求めています。第1引数は差を表現する単位を示します。
"d"
の場合は日単位です。
問題7 解答例
Sub checkEmpty() Dim row As Integer For row = 5 To 35 '開始時刻チェック If IsEmpty(Cells(row, 3).Value) Then Cells(row, 3).Interior.Color = vbYellow End If '終了時刻チェック If IsEmpty(Cells(row, 4).Value) Then Cells(row, 4).Interior.Color = vbYellow End If Next End Sub
解説
For row = 5 To 35 ~ Next
で日付列のすべてを1つ1つチェックするループを作成しています。IsEmpty
関数で該当セルが空かどうかをチェックしています。- 該当セルが空の場合は、
Cells(row, 3).Interior.Color = vbYellow
で背景色を黄色にします。 vbYellow
はカラー定数という色指定用の値です。ほかにもvbRed
(赤)、vbGreen
(緑)などがあります。
問題8 解答例
Sub calcWorkTime() Dim row As Integer Dim startTime As Date Dim endTime As Date For row = 5 To 35 If Not IsEmpty(Cells(row, 3).Value) And Not IsEmpty(Cells(row, 4).Value) Then startTime = Cells(row, 3).Value endTime = Cells(row, 4).Value Cells(row, 5).Value = DateDiff("h", startTime, endTime) End If Next End Sub
解説
- For文では行ごとの処理を行っています。
Not IsEmpty(Cells(row, 3).Value)
は開始時刻が空でない(条件①)を意味します。Not IsEmpty(Cells(row, 4).Value)
は終了時刻が空でない(条件②)を意味します。- 勤務時間を求めるには、条件①と条件②の2つを満たす必要があるため、
And
演算子で2つの条件式を並べます。 - 勤務時間はDateDiff関数で求めます。第1引数を
"h"
とすることで時間単位での差を求めることができます。
問題9 解答例
Sub insertMonthDate() Dim year As Integer Dim month As Integer '入力チェック If Not IsNumeric(Range("B2").Value) Or IsEmpty(Range("B2").Value) Then MsgBox "年には数値を入れてください" Exit Sub End If If Not IsNumeric(Range("D2").Value) Or IsEmpty(Range("D2").Value) Then MsgBox "月には数値を入れてください" Exit Sub End If year = Range("B2").Value month = Range("D2").Value 'セルをクリア Range("A5:A35").ClearContents '翌月1日を求める Dim nextMonthFirst As Date nextMonthFirst = DateSerial(year, month + 1, 1) '該当月の最終日 Dim monthLast As Date Dim lastDay As Integer monthLast = DateAdd("d", -1, nextMonthFirst) lastDay = day(monthLast) '日付を並べる Dim wk As Date Dim i As Integer wk = DateSerial(year, month, 1) For i = 1 To lastDay Range("A" & (i + 4)).Value = wk wk = DateAdd("d", 1, wk) Next End Sub
解説
- IsNumeric関数は引数の値が数値かどうかを判定します。
Not IsNumeric(Range("D2").Value)
でD2が数値でない場合を意味します。 - IsNumeric関数は値が入ってない場合にTrueを返す動作をするため、IsEmpty関数を使ってセルが空の場合も入力不正と判定するようにしています。
DateSerial(year, month + 1, 1)
で入力された西暦年と月が示す年月(以降、該当月と記載)の翌月1日を求めています。DateAdd("d", -1, nextMonthFirst)
で翌月1日から1日引くことで、該当月末日を求めています。lastDay = day(monthLast)
で該当月末日の情報から、日付のみを数値として取り出しています。- lastDayは末日を示す数値(28,30,31など)が入っていますので、その回数だけループしながら該当月の各日を表示しています。
問題10 解答例
Sub checkEmptyWeekDay() Dim row As Integer For row = 5 To 35 If Cells(row, 2).Value = "土" Or Cells(row, 2).Value = "日" Then '土日行の場合は何もしない Else '開始時刻チェック If IsEmpty(Cells(row, 3).Value) Then Cells(row, 3).Interior.Color = vbYellow End If '終了時刻チェック If IsEmpty(Cells(row, 4).Value) Then Cells(row, 4).Interior.Color = vbYellow End If End If Next End Sub
解説
基本的な処理は問題7と同様です。但し、Cells(row, 2).Value = "土" Or Cells(row, 2).Value = "日"
の条件式を使って、土日でない場合だけ未入力チェックが行われるようにしています。