検証環境: Excel 365 v2509 · Excel 2021 · Excel 2019 · 最終確認 2026-06-07
要点 — Sub(サブルーチン)は、呼び出すと実行される「名前のついた動作のかたまり」で、値は返しません。[マクロ] ダイアログから実行しているマクロの正体は、この Sub です。呼び出しは名前で行い、Call キーワードは付けても付けなくても構いません。
Sub Greet() ' Sub:名前のついた一連の動作。戻り値はない
MsgBox "こんにちは"
End Sub
Sub RunReport()
Greet ' 呼び出し — Call なし、括弧なし
Call Greet ' 結果は同じ。古い Call 記法
End Sub
呼び出し方を間違えると 「コンパイルエラー:= が必要です」「ステートメントの最後が必要です」 に行き着きます。これが Sub で最も多いつまずきです。本記事はこの「なぜ」を軸に組み立てています。
メンタルモデル:Sub は「名前で呼べる動詞」
Sub は 名前のついた動作、つまり動詞だと考えてください。FormatReport、ExportInvoices、ClearOldRows。手順を一度書いて名前を付ければ、以降はどこからでもその名前を言うだけで手順を実行できます。
ほとんどの入門書が言わない事実があります。VBA に「マクロ」という別の型は存在しません。 マクロを記録したり [開発] → [マクロ] から選んだりして実行しているのは、実体としてはただの Sub ——正確には 引数なしの Public な Sub です。「マクロ」は Excel が利用者向けに見せている呼び名にすぎず、中身は Sub。これが腑に落ちると、VBA プロジェクト全体が魔法ではなく「つなぎ合わせられる名前つき動作のリスト」に見えてきます。
たった一つのルール:呼び方が括弧の可否を決める
初心者のエラーのほとんどを説明する、覚えておくべきルールです。
' 引数なし — 3 つともすべて OK:
Greet
Call Greet
Call Greet()
' 引数あり — 正しいのはこの 2 つだけ:
SaveLog "report.txt", 3 ' ✅ そのまま呼ぶ:括弧なし、引数はカンマ区切り
Call SaveLog("report.txt", 3) ' ✅ Call を使う:括弧は必須
SaveLog("report.txt", 3) ' ❌ コンパイルエラー:= が必要です
最後の行が失敗するのは、Call がないと VBA が SaveLog( … ) を 「SaveLog を評価して戻り値を使う」 と読むからです。けれど Sub に戻り値はなく、"report.txt", 3 もそもそも単一の式ではありません。括弧は Call のもので、そのまま呼ぶときのものではない。 これは MsgBox の括弧ルールとまったく同じ理屈で、括弧は「値を使うとき」だけ現れます。
一文でいうと——そのまま呼ぶ → 括弧なし/Call で呼ぶ → 括弧あり。 どちらかに統一しましょう。最近の VBA は Call を省くのが主流です。
マクロは Public な Sub —— Private は隠す
Sub がマクロ一覧に出るかどうかは、前に付く一語で決まります。
Public Sub MonthlyClose() ' Alt+F8 のマクロ一覧に出る ——これが「マクロ」
PrepareData ' 利用者には見えない補助 Sub を呼ぶ
BuildSummary
End Sub
Private Sub PrepareData() ' マクロ一覧から隠れる ——あくまで補助
' ...
End Sub
Public(普通の Sub の既定)は「誰でも呼べて、利用者に見せる」。Private は「このモジュール内のコードだけが呼ぶ」。1 ステップずつを担う小さな補助 Sub には Private を使いましょう。マクロ一覧が散らからず、「ここは入口ではない」 という合図にもなります。引数を取る Sub も自動的に一覧から消えます。Excel には何を渡せばよいか分からないからです。
データを渡す:引数
値をベタ書きするのをやめて受け取るようにした瞬間、Sub は再利用可能になります。
Sub HighlightRow(targetRow As Long, colorIndex As Long)
Rows(targetRow).Interior.ColorIndex = colorIndex
End Sub
Sub FlagOverdue()
HighlightRow 5, 3 ' 5 行目を赤
HighlightRow 9, 6 ' 9 行目を黄
End Sub
この引数がどう伝わるか——呼ばれた Sub が、渡した変数を 書き換えられる のか——は、独立した記事に値する落とし穴です。VBA の既定は ByRef(参照渡し) なので、元の変数が知らぬ間に書き換えられることがあります。「呼び出したらカウンターが変わったのはなぜ?」の正体は ByRef vs ByVal を参照してください。
イベントプロシージャは Sub —— そうでしかありえない
あなたが書いたシート/ブックのイベントは、すべて Sub であり、選択の余地がありません。
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A:A")) Is Nothing Then
MsgBox "A 列が編集されました。"
End If
End Sub
Excel は何かが起きたとき(セルが変わる、ブックが開く)にこれらを呼び、戻り値は読み取りません。だから Sub にしかなりえず、Function にはできません。この非対称性こそ、Sub と Function の境界を最もはっきり感じさせます——呼ぶ側が答えを欲しがらないなら、それは Sub。
主張:1 つの Sub に 1 つの仕事
保守不能な VBA への最短ルートは、取り込み・整形・計算・書式・送信を一気にやる 300 行の Sub Main() です。1 つのことをする名前つき Sub に分割しましょう。
Public Sub RunPipeline()
ImportData
CleanData
BuildReport
EmailReport
End Sub
こうすると RunPipeline は目次のように読め、各ステップは単体で検証でき、送信が壊れても無関係な 250 行をスクロールせずに EmailReport だけ直せます。Sub 名は「古びない・実行されるドキュメント」 です。1 年もつ VBA と、誰も触りたがらない VBA を分けるのは、この一つの習慣です。
よくある Sub の誤り(と直し方)
| 症状 | 原因 | 直し方 |
|---|---|---|
| 呼び出しで「= が必要です」 | そのまま呼ぶのに括弧:MySub(a, b) |
括弧を外す(MySub a, b)か Call を付ける:Call MySub(a, b) |
| マクロが Alt+F8 に出ない | Sub が Private、または引数あり |
引数なしの Public にするか、引数なしの呼び出し用 Sub から呼ぶ |
| 「あいまいな名前が検出されました」 | 同じモジュールに同名の Sub が 2 つ | 片方を改名 ——名前はモジュール内で一意に |
| Sub は走るのに「何も起きない」 | 戻り値が必要な所に Sub を書いた | 呼ぶ側が答えを要るなら Function を使う |
| 引数が予期せず変わった | 既定の ByRef が変数の書き換えを許した |
引数を ByVal で宣言 —— ByRef vs ByVal 参照 |
| 「Sub または Function が定義されていません」 | 綴り違い、または別モジュール/別ブックにある | 綴りを確認。必要ならモジュール/ブックで修飾 |
マクロそのものが難所なら —— 言葉で伝えるだけでいい
作業をきれいな Sub に分けるのは良い設計ですが、それでも 書いて保守し続ける配管 です。ロジックが「この 3 ファイルを取り込み、注文 ID で突き合わせ、不一致を印付けして経理にメールする」なら、本当の仕事は Sub の切り分けではなく中身のコードです。ExcelMaster Agent なら、それを自然な日本語で言うだけでパイプライン全体を書いてくれます——Sub も Call も保守も不要。無料で試す →
関連記事
- VBA の Function とは — 戻り値とユーザー定義関数(UDF)
- VBA ByRef vs ByVal — 呼び出し後に変数が変わる理由
- VBA MsgBox の使い方 — はい/いいえ・ボタン・括弧ルール
- VBA For ループ — 実務で使う 8 つの例
よくある質問
VBA の Sub とは何ですか?
Sub(サブルーチン)は、動作を実行して値を返さない、名前のついた VBA コードのかたまりです。Sub 名前() … End Sub で定義し、名前を呼んで実行します。Excel のマクロ ダイアログから実行するマクロは Sub です。
Sub とマクロの違いは何ですか?
技術的な違いはありません。「マクロ」は、引数のない Public Sub に対する利用者向けの呼び名にすぎず、[開発] → [マクロ](Alt+F8)の一覧に出るのはこの種類だけです。すべてのマクロは Sub ですが、すべての Sub がマクロとして表示されるわけではありません。
VBA で Sub を呼び出すには?
等価な 2 通りがあります。名前だけを書く——MySub(引数つきなら MySub arg1, arg2、括弧なし)——か、Call キーワードを使う——Call MySub(arg1, arg2)(括弧は必須)。引数が複数あるそのままの呼び出しに括弧を付けるとコンパイルエラーになります。
なぜ MySub(a, b) はコンパイルエラーになりますか?
Call がないと VBA は括弧を「この Sub の戻り値を使う」と解釈しますが、Sub に戻り値はなく、a, b も単一の式ではありません。括弧を外す(MySub a, b)か、Call を付けて(Call MySub(a, b))ください。
VBA の Sub と Function の違いは?
Sub は作業をして何も返しません。Function は作業をして呼ぶ側に値を返します。呼ぶ側が答えを必要とするとき(およびワークシート関数として使いたいとき)は Function を、それ以外は Sub を使います。
VBA の Private Sub とは何ですか?
Private Sub は、そのプロシージャを同じモジュール内からのみ呼べるようにし、マクロ ダイアログから隠します。利用者が直接実行すべきでない補助に使います。Worksheet_Change などのイベントプロシージャが Private Sub なのはこのためです。
