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

Excel 2021およびMicrosoft 365で利用できる「動的配列(スピル)」は、1つのセルに入力した数式の結果が、周囲のセルへ自動的に展開される大変便利な機能です。
VBAからセルに数式を設定する場合や、スピルによって広がったセル範囲を判定・操作する場合は、従来のプロパティとは異なる評価モデルや Range
プロパティを正しく理解しておく必要があります。
動的配列非対応の古い 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 の違い(暗黙の交差評価)
これは、旧バージョンの計算エンジンとの互換性を保つため、Excelが暗黙の交差を行って結果を単一の値に強制固定しようとするからです。
' .Formula で設定すると自動的に "=@A1:A3" となり、1つの値しか返さずスピルしない
Range("B1").Formula = "=A1:A3"
' .Formula2 で設定すれば、そのまま "=A1:A3" として評価され、B1:B3 へスピルする
Range("B1").Formula2 = "=A1:A3"
数式を正常にスピルさせたい場合は、必ず .Formula2 を使用する必要があります。
IFS関数をVBAで入力するとスピルに関係なく「@」が付く現象について
この件について、以下で詳しく解説しています。
IFS関数をVBAで入力するとスピルに関係なく「@」が付く現象について|VBA技術解説
スピル範囲取得の核心:2段階アプローチ
↓.SpillParent
[親セル] (スピルを発生させているセル)
↓ .SpillingToRange
[全体範囲] (スピルにより展開されている全Range)
- SpillParent プロパティ
指定したセルがスピル範囲のメンバー(数式が入っている親セル、またはあふれた先のセルのいずれか)であれば、そのスピルを発生させている親セルを返します。 - SpillingToRange
プロパティ親セルに対してのみ動作し、スピルによって展開されている全体範囲(Range)を返します。
そのため、事前に HasSpill による確認やエラートラップを併用することが重要になってきます。
【重要】HasSpill の返り値とセルの状態(Nullと#SPILL!)
- セル A1:A3 に数値(10, 20, 30)が入力されている
- セル B1 に数式 =A1:A3 が入力され、B1:B3 へスピルしている
- セル C1 に数式 =A1:A3 を入力したが、C2 にデータがあるため #SPILL! エラーになっている
- セル D1 は何も入力されていない通常の空欄セル

| 指定する 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 を判定に使う場合は、以下のいずれかの方法をとるのが安全です。
- Target.CountLarge = 1 で事前に単一セルに絞り込む(使用例2の手法)
- If Target.HasSpill = True Then のように = True で明示的に比較する(使用例3の手法。Null や False をまとめて除外できます)
使用例
使用例1:Formula2 を使って数式を設定し、スピルさせる(作る)
Sub Sample1_Formula2()
' B1セルに動的配列数式を設定(B1:B3へスピル)
Range("B1").Formula2 = "=A1:A3"
End Sub
【注意】数式を設定するセル範囲の指定について
Range("B1:B3").Formula = "=A1"
こう書くことで、オートフィルのように参照が自動的に相対変化し、
B1 に =A1
B2 に =A2
B3 に =A3
が個別に入力されます。
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:任意セルからスピル範囲全体を取得する(親を辿る → 全体を取得)
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 を併用する理由
親セル自身に対して SpillParent を呼び出した場合は、その親セル自身を返します。
ここでは、スピル範囲全体(SpillingToRange)の取得時に予期しないエラーが発生した場合に備えて、エラートラップを併用しています。取得に失敗した場合は Nothing を返します。
使用例3:親セルからスピル範囲を取得し、値として固定化する(直接取得 → 値化)
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 を用いて安全なセルであるかを確認することが重要です。
まとめ
- Formula2(作る)
動的配列として評価させるため、数式設定時は .Formula ではなく .Formula2 を使用する。 - HasSpill(確認する)
対象セルが正常なスピル範囲に含まれているか(True か)を確認する。 - SpillParent(親を辿る)
任意のスピル先セルから、そのスピルを発生させている親セルを取得する。 - SpillingToRange(全体を取得する)
親セルから、スピルによって展開されている全体範囲(Range)を取得する。
サイト内の関連ページ
同じテーマ「マクロ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.
