🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA で WorksheetFunction を使う — Excel 自身の関数をコードから呼ぶ(そして 2 通りの失敗の仕方)

|

Excel VBA で WorksheetFunction を使う — Excel 自身の関数をコードから呼ぶ(そして 2 通りの失敗の仕方)

TL;DRApplication.WorksheetFunction は、VBA から Excel の 450 を超える組み込み関数に 手を伸ばす方法です。だから SUMVLOOKUPCOUNTIF を手書きのループで書き直す必要は ありません。呼び出し方は 2 通り あり、その違いこそがすべてです。 Application.WorksheetFunction.VLookup(...) は一致がない瞬間に 実行時エラーを発生させます — 成功が期待でき、取りこぼしは大きく騒ぐべきときに使いましょう。Application.VLookup(...).WorksheetFunction を外す)は IsError でテストできる エラー値を返します — 取りこぼしが 普通に起きるときに使いましょう。そして Application.X の結果を受ける変数は Variant で なければなりません。さもないと、テストする前に error 13 で落ちます。

' "West" は B 列に何回現れる? 1 行で、ループなし。
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Sales")
Dim n As Long
n = Application.WorksheetFunction.CountIf(ws.Columns("B"), "West")
MsgBox "West appears " & n & " times"

列を合計するため、あるいは値を引くために For Each ループに手を伸ばすこと — それが、VBA が 遅さとバグを同時に抱え込む最もよくある道筋です。Excel にはすでに計算エンジンが載っていて — 何百もの磨き上げられた関数が — WorksheetFunction はその扉です。身につけるべき技術は、より 多くのコードを書くことではありません。Excel がすでにその関数を持っていると気づいて、それを 呼ぶことです。本記事は、誰もがつまずくたった 1 つの事実 — 呼び出し方は 2 通りあり、正反対の 仕方で失敗する — を軸に組み立てられています。

この記事で学べること

  • 考え方の軸 — Excel のエンジンを借りる。ループで作り直さない
  • 最も大事なルール — WorksheetFunction.X は失敗でクラッシュし、Application.X はテストできるエラーを返す
  • 型の罠 — なぜ結果を受ける変数は Variant でなければならないのか
  • 呼べる関数、呼べない関数、そして呼ぶ べきでない 関数
  • 1 セルずつループする代わりに範囲全体を渡す
  • WorksheetFunction と、セルに数式文字列を書き込むこと

考え方の軸:エンジンを借りる。作り直さない

あなたが知っているワークシート関数はすべて — SUMAVERAGEVLOOKUPMATCHCOUNTIFSUMIFMAXTRIMPROPERApplication.WorksheetFunction を通して VBA から使えます。 呼んでいるのは関数の VBA 版コピーではありません。シートが使うのと同じエンジン を呼んで いるので、結果は数式とまったく一致します。

これが大事なのは、代わりの手段がほぼ必ずより悪いからです。列を合計する、一致を数える、 ルックアップのために走査する For Each ループは、Excel がすでに最適化した 1 つの関数よりも、 書くのが長く、走るのが遅く、間違えやすいものです。WorksheetFunction.Sum(ws.Range("B2:B100000")) は 1 回の走査で返りますが、ループでの等価物は 10 万回の反復を解釈実行の VBA ですり潰して いきます。このイメージ — Excel がその関数を持っている、私はただ呼べばいい — を頭に置いて おけば、「VBA で X を計算するには?」という質問のほとんどはひとりでに答えが出ます。

最も大事なルール:2 つの呼び出し方、2 つの失敗モード

持ち帰るべきはこの 1 点です。同じ 関数を 2 通りで呼べますが、操作が 失敗 したとき — たとえばルックアップが何も見つけられなかったとき — 両者はまるで違う振る舞いをします。

' スタイル 1: WorksheetFunction.X - 一致なしでクラッシュする。
Dim price As Double
price = Application.WorksheetFunction.VLookup("Widget", ws.Range("A:C"), 3, False)
' "Widget" がなければ: 実行時エラー 1004 が出て、実行が止まる。
' スタイル 2: Application.X(.WorksheetFunction なし)- テストできるエラーを返す。
Dim result As Variant
result = Application.VLookup("Widget", ws.Range("A:C"), 3, False)
If IsError(result) Then
    MsgBox "Widget not found"      ' きれいに処理、クラッシュなし
Else
    MsgBox "Price is " & result
End If

同じ関数、同じ引数 — なのに WorksheetFunction.VLookup は一致がないと 例外を投げApplication.VLookupIsError が捕まえる #N/A エラー値を 返します。どちらが「正しい」 ということはありません。両者は違う意図のためのものです。

  • 操作が成功すると 期待 でき、失敗が本当に何かおかしいことを意味するなら WorksheetFunction.X を使いましょう。クラッシュは機能です — 悪い値を下流に流す代わりに、 マクロを止めてくれます。
  • 取りこぼしが処理したい普通の結果なら Application.X を使いましょう — キーが見つかるとは 限らないルックアップ、たいていは存在する値。IsError でテストして分岐します。

このトピック全体で第 1 位のバグは、何かが存在するか どうかを調べる ために WorksheetFunction.Match を使い、存在しないときに error 1004 に驚くことです。存在チェックこそ、 Application.Match + IsError の出番です。

型の罠:結果は Variant でなければならない

スタイル 2 が働くのは、結果を受ける変数がエラー値を 保持 できるときだけです。VBA では Variant だけがそれをできます。それより狭い型で宣言すると、代入そのものが吹き飛びます。

Dim result As Double
result = Application.VLookup("Widget", ws.Range("A:C"), 3, False)
' 見つからなければ: error 13「型が一致しません」- Double は #N/A を保持できないから

直し方は単純に Dim result As Variant です。そうすれば IsError(result) を安全に呼べ、 成功時には値をそのまま使えます。これは「エラーを返す」パターンの、静かな後半です。 Application.X の結果は、必ず Variant に入れる。 これを忘れると、型の不一致が、まさに 組もうとしていたエラー処理そのものを覆い隠してしまいます。

呼べる関数 — そして呼ぶべきでない関数

ライブラリのほとんどは使えますが、知っておく価値のある 3 つの縁があります。

  • すべてが公開されているわけではありません。 新しめの、あるいは揮発性の関数のいくつかは WorksheetFunction に現れません。名前が見当たらないときは、たいてい Application.Evaluate に 頼るか、数式をセルに書き込めます(後述)。
  • VBA がすでにネイティブで持つ関数もあります — そちらを使いましょう。 WorksheetFunction.LeftMidRightTrimUpperLower呼んではいけません。 VBA には自前の LeftMidRightTrimUCaseLCase があり、より速く、Excel への 往復もありません。(1 つ微妙な点。VBA の Trim は先頭と末尾の空白だけを取り除きますが、 WorksheetFunction.Trim は内部の連続空白もまとめます — なので両者は同一ではなく、ときには 本当に ワークシート版が欲しいこともあります。)
  • 名前が違うこともあります。 VBA のメンバー名はたいてい関数と一致しますが、いくつかは Excel の古い内部表記を引きずっています。迷ったら Application.WorksheetFunction. と打って、 IntelliSense に実際にあるものを並べさせましょう。

目安はこうです。ルックアップ、条件付きの集計や合計、統計といった、Excel が得意な重量級の 分析関数には WorksheetFunction に手を伸ばし、基本的な文字列や数値の作業には VBA 自前の キーワードを使う。

1 セルずつループせず、範囲全体を渡す

最大の速度向上は、同時に最も見落としやすいものでもあります。WorksheetFunction の関数は 範囲 を取るので、ループして 1 セルずつ呼ぶ代わりに、範囲全体を一度に手渡しましょう。

' 遅い - 行ごとに 1 回エンジンを呼ぶ。
Dim i As Long, total As Double
For i = 2 To lastRow
    total = total + ws.Cells(i, "B").Value
Next i

' 速い - 呼び出しは 1 回、ループはエンジンが内部でやる。
total = Application.WorksheetFunction.Sum(ws.Range("B2:B" & lastRow))

速い版は単に短いだけではありません。反復を、解釈実行の VBA で回す代わりに、Excel の コンパイル済みエンジンへ押し下げます。同じことが CountIfSumIfAverageMaxMin にも 当てはまります — 範囲を渡して、数える仕事は任せましょう。ループの中で合計を積み上げている 自分に気づいたら、それはほぼ必ず、呼ばれるのを待っているワークシート関数です。

WorksheetFunction と、セルに数式を書き込むこと

3 つ目の選択肢があり、いつそれを選ぶべきかを知っておくと、コードが正直なままでいられます。 WorksheetFunctionコードの中で値を一度だけ計算します — シートは変わらず、データが 変わっても答えは再計算されません。セルに数式文字列を書き込むこと (ws.Range("D2").Formula = "=SUM(B2:B100)")は、永遠に更新され続ける 生きた数式を残します

ロジックの中で いま 数値が必要なとき — 比較するしきい値、分岐の判断に使うカウント、 レポートに刻む合計 — には WorksheetFunction を使いましょう。ユーザーが編集しても正しいまま であるべき結果を見せたいときは、セルに数式を書き込みましょう。WorksheetFunction に手を伸ばして、 その静的な答えを、本来数式があるべき場所に貼り付けること — それは、レポートが静かに古びて いくよくある道筋です。

ExcelMaster の活用

WorksheetFunction は、驚くほど多くの判断を 1 回の呼び出しに詰め込みます — 2 つのスタイルの どちらを使うか、結果に Variant が要るか、ネイティブの VBA キーワードのほうが良いか、値を 一度だけ計算すべきか生きた数式として残すべきか。そのどの選択にも、間違った答えを返す — あるいはテストしていないデータでクラッシュする — 失敗モードが潜んでいます。

ExcelMaster なら、 計算を説明するだけで済みます。「West 地域からの注文が何件あるか数えて」「各商品の価格を引いて、 在庫にないものにフラグを立てて」と言えば、正しい呼び出し方を選び — 取りこぼしが本当のエラーに なるクラッシュする方、取りこぼしが想定内のテストできる方 — 必要なときは結果を Variant で宣言し、 ループせずに範囲全体を渡します。ブックもコードもあなたの手元に残り、処理されなかった error 1004 が レポートの途中でマクロを止める、あの一幕だけを飛ばせます。

よくある質問

VBA の WorksheetFunction と Application の違いは?

どちらも同じ Excel 関数を呼びますが、失敗の仕方が違います。Application.WorksheetFunction.X は、 一致のないルックアップのように関数が結果を返せないとき、実行時エラー(たいてい 1004)を発生 させます。Application.X.WorksheetFunction なし — は代わりに #N/A のような Excel の エラー値を返し、これを IsError でテストします。失敗がマクロを止めるべきときは前者を、 取りこぼしが処理すべき普通のケースのときは後者を使いましょう。

WorksheetFunction.VLookup で error 1004 が出るのはなぜ?

WorksheetFunction.VLookup が、値が見つからないときに #N/A を返すのではなく実行時エラーを 投げるからです。そこでの error 1004 は、壊れた数式ではなく、ほぼ必ず「一致なし」を意味します。 いくつかのルックアップが外れると見込むなら、Application.VLookupVariant に呼び入れて IsError(result) でテストするか、WorksheetFunction の呼び出しを On Error 処理で包みましょう。

Application.VLookup で型の不一致(error 13)が出るのはなぜ?

Application.VLookup はエラー値を返しうるのに、それを保持できるのは Variant だけだからです。 受け取る変数を DoubleLongString で宣言すると、結果が #N/A になった瞬間に error 13 が 起きます。As Variant で宣言し、値を使う前に IsError を呼びましょう。

WorksheetFunction を通せば、どんな Excel 関数でも VBA で使える?

ほとんどは使えますが、すべてではありません。よく使う分析関数 — VLOOKUPMATCHCOUNTIFSUMIFSUMAVERAGE、統計系 — はすべてそろっています。新しめの、あるいは揮発性の関数の いくつかは公開されていません。それらには Application.Evaluate を使うか、数式をセルに書き込み ましょう。そして基本的な文字列や数値には、ワークシート版よりも VBA 自前の LeftMidTrimUCase や演算子を選びましょう。

WorksheetFunction.Sum は VBA でループするより速い?

はい、大きな範囲でははっきりと。範囲全体を WorksheetFunction.Sum に渡すと、反復は 1 回の 呼び出しで Excel のコンパイル済みエンジンの中で走りますが、For EachFor のループは解釈 実行の VBA で 1 セルずつ走ります。ループの中で合計やカウントを積み上げているときはいつでも、 範囲全体に対して呼ぶワークシート関数のほうが、たいてい短くて速いのです。

検証環境

動作確認: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-10。

関連ガイド: VBA VLOOKUP · VBA Remove Duplicates · VBA Advanced Filter · VBA For Loop · VBA Range