VBA入門
スピルとVBA(Formula2とスピル範囲の取得)

ExcelマクロVBAの基本と応用、エクセルVBAの初級・初心者向け解説
公開日:2026-09-08 最終更新日:2026-09-18

第144回.スピルとVBA(Formula2とスピル範囲の取得)


スピルとVBA(Formula2とスピル範囲の取得)

Excel 2021およびMicrosoft 365で利用できる「動的配列(スピル)」は、1つのセルに入力した数式の結果が、周囲のセルへ自動的に展開される大変便利な機能です。
VBAからセルに数式を設定する場合や、スピルによって広がったセル範囲を判定・操作する場合は、従来のプロパティとは異なる評価モデルや Range プロパティを正しく理解しておく必要があります。


今回は、動的配列に対応した数式設定(Formula2)と、スピル範囲の親セルおよび全体範囲を取得・判定するための Range プロパティについて解説します。

※本記事で解説するプロパティは、動的配列に対応した Excel(Excel 2021 以降および Microsoft 365)でのみ利用可能です。
動的配列非対応の古い Excel バージョンではコンパイルエラーまたは実行時エラーとなりますのでご注意ください。


概要・構文

セルに数式を設定するプロパティ

プロパティ 概要
Range.Formula2 動的配列対応の数式として設定します。
配列を返す数式を設定した場合、その結果がセル範囲へそのままスピルします。(Microsoft推奨)
【同系プロパティ】
・.Formula2Local(日本語等のローカル関数名表記)
・.Formula2R1C1(R1C1参照形式)
・.Formula2R1C1Local(ローカル表記のR1C1参照形式)
Range.Formula 従来の互換性を保つための数式設定です。
暗黙の交差(Implicit Intersection)評価を行うため、必要に応じて @ 演算子が挿入されます。
Formulaで設定した数式は暗黙の交差評価になるためスピルしません。
【同系プロパティ】
・.FormulaLocal(日本語等のローカル関数名表記)
・.FormulaR1C1(R1C1参照形式)
・.FormulaR1C1Local(ローカル表記のR1C1参照形式)

スピル範囲を判定・取得するプロパティ

プロパティ 戻り値 概要
Range.HasSpill Variant 指定範囲のセルが「スピル範囲のメンバー(正常にスピルしている範囲に属するセル)」であるかを示します。
全セルが該当なら True、全く含まなければ False、混在していれば Null を返します。
Range.SpillParent Range スピル範囲のメンバーであるセルから、そのスピルを発生させている親セルを返します。
(※スピル範囲外のセルで呼び出すとエラーになります)
Range.SpillingToRange Range スピルを発生させている親セルから、スピル全体のセル範囲を返します。
(※親セル以外のセルや、スピルしていないセルで呼び出すとエラーになります)


解説

Formula と Formula2 の違い(暗黙の交差評価)

VBAでセルの .Formula(スピル非対応)プロパティに数式を入れるとき、その数式が「スピル数式」(複数セルに結果を出力する数式)であれば、関数の先頭または引数のセル範囲の先頭に @(暗黙の交差演算子)が自動的に追加されます。
これは、旧バージョンの計算エンジンとの互換性を保つため、Excelが暗黙の交差を行って結果を単一の値に強制固定しようとするからです。

' .Formula で設定すると自動的に "=@A1:A3" となり、1つの値しか返さずスピルしない
Range("B1").Formula = "=A1:A3"

' .Formula2 で設定すれば、そのまま "=A1:A3" として評価され、B1:B3 へスピルする
Range("B1").Formula2 = "=A1:A3"

数式を正常にスピルさせたい場合は、必ず .Formula2 を使用する必要があります。

IFS関数をVBAで入力するとスピルに関係なく「@」が付く現象について

IFS関数は、スピルするかどうかにかかわらず、常に関数の先頭または引数のセル範囲の先頭に「@」が自動的に追加されます。
この件について、以下で詳しく解説しています。
IFS関数をVBAで入力するとスピルに関係なく「@」が付く現象について|VBA技術解説
・そもそも「@」とは ・VBAでセルに数式を入れる場合 ・「@」(インターセクション演算子)が勝手についてしまう関数

スピル範囲取得の核心:2段階アプローチ

任意のセルからスピル範囲全体を取得するには、「対象セル → 親セル(起点) → 全体範囲」 という2段階のステップを踏む必要があります。

[対象セル] (スピル範囲のメンバー)
↓.SpillParent
[親セル] (スピルを発生させているセル)
↓ .SpillingToRange
[全体範囲] (スピルにより展開されている全Range)


  • SpillParent プロパティ
    指定したセルがスピル範囲のメンバー(数式が入っている親セル、またはあふれた先のセルのいずれか)であれば、そのスピルを発生させている親セルを返します。
  • SpillingToRange
    プロパティ親セルに対してのみ動作し、スピルによって展開されている全体範囲(Range)を返します。
※ SpillParent も SpillingToRange も、前提条件を満たさないセル(スピル範囲外のセルなど)に対して実行すると実行時エラーが発生します。
そのため、事前に HasSpill による確認やエラートラップを併用することが重要になってきます。

【重要】HasSpill の返り値とセルの状態(Nullと#SPILL!)

HasSpill は戻り値が Variant 型となっており、判定対象のセル範囲(単一セルか複数セルか)やスピルの状態によって返り値が変わります。

具体的な画面例と各セルの値
次のようなシート構成を例に考えてみます。
  • セル A1:A3 に数値(10, 20, 30)が入力されている
  • セル B1 に数式 =A1:A3 が入力され、B1:B3 へスピルしている
  • セル C1 に数式 =A1:A3 を入力したが、C2 にデータがあるため #SPILL! エラーになっている
  • セル D1 は何も入力されていない通常の空欄セル
スピルとVBA(Formula2とスピル範囲の取得)

このとき、指定する Range(セル範囲)ごとの HasSpill の返り値は以下のようになります。

指定する Range 返り値 状態と理由
Range("B1") TRUE スピルを発生させている親セル(正常に展開中)
Range("B2") TRUE スピルによって結果が表示されているメンバー(展開先)
Range("D1") FALSE スピルしていない通常のセル
Range("C1") FALSE 【注意】 数式は入っているが、妨害データにより #SPILL! エラーとなっており、実際にはスピルしていないため False となる
Range("B1:B3") TRUE 指定範囲内の全セルがスピル範囲に含まれている
Range("D1:D3") FALSE 指定範囲内の全セルがスピル範囲に含まれていない
Range("B1:D1") Null 【注意】 スピルセル(B1)と非スピルセル(C1, D1)が混在しているため Null となる

VBAでの判定時の注意点
HasSpill が Null を返す可能性があるため、複数セルを含む Range に対して直接 If Range("B1:D1").HasSpill Then のように判定すると、VBAでは 「型が一致しません(エラー13)」 が発生します。
そのため、実務で HasSpill を判定に使う場合は、以下のいずれかの方法をとるのが安全です。
  • Target.CountLarge = 1 で事前に単一セルに絞り込む(使用例2の手法)
  • If Target.HasSpill = True Then のように = True で明示的に比較する(使用例3の手法。Null や False をまとめて除外できます)


使用例

使用例1:Formula2 を使って数式を設定し、スピルさせる(作る)

セル A1:A3 にデータが入っている状態で、セル B1 に動的配列数式を設定してスピルさせる基本的な例です。

Sub Sample1_Formula2()
  ' B1セルに動的配列数式を設定(B1:B3へスピル)
  Range("B1").Formula2 = "=A1:A3"
End Sub

【注意】数式を設定するセル範囲の指定について
従来(Excel 2019以前や .Formula)であれば、A1:A3 の値を B列にそれぞれ参照させたい場合、セル範囲全体を指定して次のように記述していました。
Range("B1:B3").Formula = "=A1"
こう書くことで、オートフィルのように参照が自動的に相対変化し、
B1 に =A1
B2 に =A2
B3 に =A3
が個別に入力されます。

しかし、動的配列数式(スピル)を使う .Formula2 でこれをやってしまうと問題が起こります。
Range("B1:B3").Formula2 = "=A1:A3"
このように記述すると、B1、B2、B3 の すべてのセルにそれぞれ =A1:A3 というスピル数式が入力されてしまいます。
結果として、3つのセル全員が B1:B3 にスピルしようとお互いの領域を横取りし合う形になり、#SPILL! エラー になってしまいます。
.Formula2 でスピル数式を設定する際は、セル範囲ではなく「起点となる先頭の1セル」だけに設定するのが正しい書き方です。
誤り: Range("B1:B3").Formula2 = "=A1:A3" (B1~B3 すべてに数式がセットされ #SPILL! になる)
正しい: Range("B1").Formula2 = "=A1:A3" (B1 だけに設定すれば、B1:B3 へ自動展開される)

使用例2:任意セルからスピル範囲全体を取得する(親を辿る → 全体を取得)

任意の単一セルを受け取り、そのセルが属するスピル範囲全体(Range)をエラートラップを併用して返す汎用関数です。

Function GetSpillRange(ByVal Target As Range) As Range
  ' 「指定された1セルが属するスピル範囲」を求めるため、複数セル指定時は除外
  If Target.CountLarge > 1 Then Exit Function
  
  ' 単一セルに限定しているため HasSpill は True / False で返る
  ' スピル範囲外や #SPILL! エラー時は False となるため、ここで除外
  If Not Target.HasSpill Then Exit Function
  
  ' 対象セル -> SpillParent(親セル) -> SpillingToRange(全体範囲) の順に取得
  ' スピル範囲の取得時に予期しないエラーが発生した場合に備えて、
  ' On Error Resume Next を使い、取得に失敗した場合は Nothing を返します
  On Error Resume Next
  Set GetSpillRange = Target.SpillParent.SpillingToRange
  If Err.Number <> 0 Then
    Set GetSpillRange = Nothing
    Err.Clear
  End If
  On Error GoTo 0
End Function

Sub Sample2_TestGetSpillRange()
  Dim spillRng As Range
  
  ' アクティブセルが含まれるスピル範囲を取得
  Set spillRng = GetSpillRange(ActiveCell)
  
  If Not spillRng Is Nothing Then
    MsgBox "スピル範囲アドレス: " & spillRng.Address
    ' 例:スピル範囲全体に外枠罫線を引く
    spillRng.BorderAround LineStyle:=xlContinuous
  Else
    MsgBox "選択セルは有効なスピル範囲内ではありません。"
  End If
End Sub

【ポイント】On Error を併用する理由
Target.SpillParent は、スピル範囲内のセルから親セルを取得するためのプロパティです。
親セル自身に対して SpillParent を呼び出した場合は、その親セル自身を返します。
ここでは、スピル範囲全体(SpillingToRange)の取得時に予期しないエラーが発生した場合に備えて、エラートラップを併用しています。取得に失敗した場合は Nothing を返します。

使用例3:親セルからスピル範囲を取得し、値として固定化する(直接取得 → 値化)

親セルであることが分かっている場合に、SpillingToRange で直接全体範囲を取得し、数式を削除して「値」に変換する処理です。

Sub Sample3_FixSpillValues()
  Dim baseCell As Range
  Dim spillRng As Range
  
  ' スピルを発生させている親セルを指定
  Set baseCell = Range("B1")
  
  ' 親セルが正常にスピルしているか確認(NullやFalseを除外するため = True で比較)
  If baseCell.HasSpill = True Then
    ' 親セルから直接、全体範囲を取得
    Set spillRng = baseCell.SpillingToRange
    
    ' 範囲全体を配列として一括で読み込み、そのまま書き戻す(自己代入)
    ' これにより数式が削除され、計算結果の値だけがセルに固定化されます
    spillRng.Value = spillRng.Value
    
    MsgBox "スピル数式を削除し、結果を値として固定化しました: " & spillRng.Address
  End If
End Sub


スピル範囲の消去と「ゴースト(Ghost)」

現象スピルによって自動展開されているセル(子セル)に表示されている値は、親セルの数式評価によって一時的に投影されている実体のない値(通称:ゴースト)です。
そのため、VBAからスピル結果を操作・削除する際は以下の点に留意する必要があります。
  • スピル範囲を一括消去したい場合
    スピル展開されている子セルの値を .ClearContents 等で消去しようとしても、親セルに数式が残っている限り再計算されて即座に復元されます。
    スピル範囲全体をクリアしたい場合は、親セル(起点)の数式または内容を消去(baseCell.ClearContents)するだけで、展開されていた領域全体が一括して消去されます。
  • ゴーストセルへの直接書き込みによる #SPILL! エラー
    VBAでスピル先(子セル)に対して値や別の数式を直接書き込むと、親セルのスピル範囲が妨害(ゴーストが実体セルで遮断)され、親セルが #SPILL! エラー に変化します。
    スピル範囲内へVBAで別の処理を行う際は、事前に HasSpill や SpillParent を用いて安全なセルであるかを確認することが重要です。


まとめ

動的配列(スピル)を VBA で扱う際は、以下の4つのプロパティの役割分担を意識してセットで運用するのが基本です。
  • Formula2(作る)
    動的配列として評価させるため、数式設定時は .Formula ではなく .Formula2 を使用する。

  • HasSpill(確認する)
    対象セルが正常なスピル範囲に含まれているか(True か)を確認する。

  • SpillParent(親を辿る)
    任意のスピル先セルから、そのスピルを発生させている親セルを取得する。

  • SpillingToRange(全体を取得する)
    親セルから、スピルによって展開されている全体範囲(Range)を取得する。

この役割構造さえしっかり押さえておけば、スピル機能を活かした安全で読みやすい VBA プログラムが書けるようになります。


サイト内の関連ページ

スピルについて|エクセル入門
・スピルとは ・スピルの数式例 ・ゴースト ・スピル範囲での独特な挙動について ・スピルのエラー表示 ・スピル範囲演算子 ・暗黙的なインターセクション演算子 ・従来のスピルしないエクセルとの互換性についての注意点 ・スピル関連用語のまとめ ・スピル関連記事
スピルでVBAの何が変わったか|VBA技術解説
・Rangeオブジェクトに追加されたプロパティ ・セルに数式を設定する場合 ・1次元配列を返すユーザー定義関数 ・2次元配列を返すユーザー定義関数 ・JAG配列を返すユーザー定義関数 ・スピルのVBAでの活用について




同じテーマ「マクロVBA入門」の記事

第83回.RangeのOffsetプロパティ
第84回.RangeのAddressプロパティ
第85回.結合セルの扱い
第144回.スピルとVBA(Formula2とスピル範囲の取得)
第86回.総合練習問題10
第88回.並べ替え(Sort)
第89回.オートフィルター(AutoFilter)
第90回.フィルターオプションの設定(AdvancedFilter)
第91回.条件付き書式(FormatCondition)
第126回.入力規則(Validation)
第92回.名前定義(Names)


新着記事NEW ・・・新着記事一覧を見る

Excelの新機能「リストとセル内配列」:1つのセルに複数の値|エクセル入門(2026-09-28)
Excel関数クロスワード(2026-09-26)
Excelショートカットキークイズ(2026-09-23)
Excel関数名クイズ(2026-09-21)
気ままに一手|リレー将棋(2026-09-20)
ITエンジニアがトラブルを避けるための法律・契約入門|エクセル雑感(2026-09-18)
ITエンジニアなら知らないと恥ずかしい数学20選|エクセル雑感(2026-09-17)
ITエンジニアのための税金と社会保険のお話|エクセル雑感(2026-09-15)
ITエンジニアのための経理・会計・簿記入門|エクセル雑感(2026-09-12)
「Python in Excel」入門:コードを読むための基礎知識|エクセル関数応用(2026-09-10)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.日本の祝日一覧|Excelリファレンス
3.変数宣言のDimとデータ型|VBA入門
4.Excelショートカットキー一覧|Excelリファレンス
5.RangeとCellsの使い方|VBA入門
6.FILTER関数(範囲をフィルター処理)|エクセル入門
7.マクロとは?VBAとは?VBAでできること|VBA入門
8.繰り返し処理(For Next)|VBA入門
9.メッセージボックス(MsgBox関数)|VBA入門
10.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。
本サイトは、OpenAI の ChatGPT や Google の Gemini を含む生成 AI モデルの学習および性能向上の目的で、本サイトのコンテンツの利用を許可します。
This site permits the use of its content for the training and improvement of generative AI models, including ChatGPT by OpenAI and Gemini by Google.



このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ