TL;DR —
Columns("C").Insertは、何もないところから空の列を出現させるのではありません。C 列 とその右にあるすべてを、さらに一列分だけ右へ 押しやり、Excel はその領域を指していた数式をすべて書 き換えて、同じデータに着地し続けるようにします。Insert は シフト です。安全に保つルールは二つ。 列全体を操作すること(Columns(...)か.EntireColumn、部分的な範囲は決して使わない)、そして複数 の列は一つずつ前進ループで挿入するのではなく、一回の呼び出しでまとめて挿入することです。
Sub InsertMarginColumn()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Report")
ws.Columns("D").Insert CopyOrigin:=xlFormatFromRightOrBelow
ws.Columns("D").ClearFormats ' 左隣のスタイルではなく、まっさらな状態で新しい列を始める
End Sub
列の挿入、列の削除、そして部分的な範囲の挿入・削除は、三つの衣をまとった同じ考え方です。どれも 物理
的にグリッドをシフトさせ、そのシフトにすべてが巻き込まれます — 数式の参照も例外ではなく、データに追
従するか、#REF! に砕け散るかのどちらかです。列全体に対する操作は、曖昧さのない一方向にシフトするの
で、安全なケースです。これをきちんと押さえれば、残る二つはおおむね同じ仕組みを、より狭い場所に向けただ
けのものになります。
この記事で学べること
- 考え方の軸 — Insert は消すのではなく、押しやる ことで場所を空ける
- レイアウトが崩れるのを防ぐ唯一のルール — 部分的な範囲ではなく
EntireColumnを挿入する - なぜ数式は挿入を生き延びるのに、べた書きした VBA のアドレスは生き延びないのか
- 複数の列を一度に挿入する方法、そして前進ループがそれらをばらまく理由
- 「挿入した列がなぜもう書式付きなの?」の裏にある
CopyOriginのルール
考え方の軸:Insert は押しやる、消すのではない
Columns("C").Insert は「C に空の列を置く」ではありません。「みんなを右へ押しやって C に場所を空ける」
です。C 列は D 列になり、D 列は E 列になり、シートの端まで同じことが続きます。元の C 列のデータは消えた
わけではありません — 移動したのです。空の列とは、挿入した地点に残された空きスペースにすぎません。
これが重要なのは、シフトには、単なるクリアにはない帰結があるからです。データが動くと、Excel は参照もそ
れに連れて動かします。三枚離れたシートにある =SUM(C2:C100) という数式は、C の前に挿入した瞬間に
=SUM(D2:D100) になります。Excel が同じ数値を指し続けさせているからです。これは仕様です。落とし穴はこ
の先にあって、あなたの VBA コードは同じ扱いを受けないのです。
最も大事なルール:EntireColumn を挿入する
信頼できる挿入は、どれも 列全体 に対して行われます。
ws.Columns("C").Insert ' C の前に列を丸ごと一本挿入
ws.Range("C:C").EntireColumn.Insert ' 同じ意味を明示的に書いた形
レイアウトを崩す一番の方法は、代わりに 部分的な 範囲を挿入することです。
ws.Range("C1:C10").Insert Shift:=xlShiftToRight ' 10 個のセルだけを右へシフトする
これは 10 個のセルだけを右へ押しやり、C 列の残りはその場に留めます — グリッドの真ん中に打ち込まれたギ
ザギザの段差で、11 行目以降が 1〜10 行目に対してずれてしまいます。エラーは出ず、誰かが下へスクロールす
るまでは問題なく見えます。ルールは単純です。列 を挿入したいなら、列 を指定する — Columns(...) か
.EntireColumn です。部分的な範囲の挿入も立派な道具ですが、それは別の仕事であり(VBA セルの挿入
で扱います)、「列」のつもりでそれに手を伸ばすのがバグの正体です。
数式はデータに追従する — が、あなたのコードはしない
人を驚かせる非対称がこれです。C の前に列を挿入すると、こうなります。
- ワークシートの数式は調整されます。
=D5*E5、=VLOOKUP(A2, C:F, 2, 0)、グラフのもとになる範囲 — Excel はそれらすべてを書き換え、同じデータを指し続けるようにします。あなたが手を触れる必要はありませ ん。 - VBA にべた書きしたアドレスは調整されません。 マクロがあとで
ws.Range("D5").Value = 100を走ら せると、そのリテラルの"D5"は依然として D 列 5 行目のセルを意味します — が、挿入のあとでは、それは あなたが思い描いていたのとは 別の セルです。文字列は、自分の左に列が現れたことを知りません。
つまり危険なのは挿入そのものではなく、古いレイアウトを前提にした、挿入 より前 に書かれたコードです。 防御策は二つ、好ましい順に挙げます。
' 1. 挿入する前に、必要なものをオブジェクトとして捕まえておく - オブジェクトは移動に追従する
Dim total As Range
Set total = ws.Range("D5")
ws.Columns("C").Insert
total.Value = 100 ' まだ正しいセル。オブジェクトがシフトに追従した
' 2. あるいは挿入した後で見出し名から列を探す。固定した列文字では決してしない
Dim col As Long
col = ws.Rows(1).Find("Amount", LookAt:=xlWhole).Column
判断はこうです。リテラルのセルアドレスは、その近くで挿入や削除をした瞬間に、すべて陳腐化したものとして
扱ってください。参照は Range オブジェクトとして握るか、名前で見つけられる見出しから引き当てます。
一回の呼び出しで複数の列を挿入する
3 列挿入するには、3 列分の範囲を挿入します。
ws.Columns("C:E").Insert ' 一回のシフトで C の前に 3 列が現れる
1 列の挿入を前進ループで 3 回繰り返しては いけません。
Dim i As Long
For i = 1 To 3
ws.Columns("C").Insert ' 誤り - 挿入するたびに次の挿入位置が押しやられる
Next i
Insert はそのたびに右側すべてに番号を振り直すので、二回目の反復での「C」はあなたが思う場所ではありま
せん。きれいなひとまとまりの代わりに、シート中に散らばった列ができあがります。これは、前進ループでの
削除 が列を飛ばすのと同じ番号振り直しの罠 — その鏡像で、VBA 列の削除
で扱います。ブロックは一つの文で挿入するか、位置が計算されてループが避けられないなら、右から左へ 進
めて、先の挿入が後の対象を決して動かさないようにします。
CopyOrigin:新しい列が最初から書式付きで現れる理由
挿入したばかりの列は、本当の意味では空ではありません — 既定では、左隣 の列の 書式 を受け継ぎます
(CopyOrigin:=xlFormatFromLeftOrAbove が既定です)。左隣が太字の合計や網掛けの帯なら、あなたの「空
の」新しい列も太字や網掛けで現れます。これが「挿入した列がなぜもう書式付きなの?」の答えです。
ws.Columns("D").Insert CopyOrigin:=xlFormatFromRightOrBelow ' 代わりに右隣の書式を受け継ぐ
' - または - 既定のまま挿入し、あとから消す:
ws.Columns("D").Insert
ws.Columns("D").ClearFormats
意図をもって選んでください。書式付きのブロックを延ばしているなら左から受け継ぐのが正解、本当にまっさら な列が欲しいならクリアが正解です。既定に任せて驚く、というのが避けたいことです。
ExcelMaster の活用
列の挿入は一行に見えて、三つの判断を隠しています — 列全体を挿入する(部分的な範囲ではなく)、シフトを またいでも後続の参照を有効に保つ、そして新しい列がどの隣の書式を受け継ぐかを制御する — そしてどれを間 違えても、静かに失敗します。崩れたレイアウト、間違ったセルに書き込むようになったマクロ、あるいは紛れ込 んだ太字の列です。
ExcelMaster には、望むことを
そのまま伝えられます — 「Amount の後ろに余白の列を挿入して、書式は空で、合計の数式はそのまま保って」 —
すると、EntireColumn.Insert を書き、固定した列文字ではなく見出しから列を見つけ、それに合わせて
CopyOrigin を設定(あるいは書式をクリア)し、複数列を頼めば一回の呼び出しでまとめて挿入します。ブック
とコードはあなたの手元に残ります。
よくある質問
VBA で列を挿入するには?
Columns("C").Insert を使うと、C 列の前に列を丸ごと一本挿入できます。C から右のすべてが一列分右へシフ
トし、それらのセルを参照していたワークシートの数式は自動的に調整されます。ThisWorkbook.Worksheets("Report").Columns("C").Insert
のように修飾した形が好ましく、たまたまアクティブなシートに依存しなくなります。
複数の列を一度に挿入するには?
複数列分の範囲を挿入します。Columns("C:E").Insert は、一回のシフトで C の前に 3 列を挿入します。
Columns("C").Insert を 3 回ループしてはいけません — 挿入するたびに後ろの列の番号が振り直され、繰り返
しが間違った場所に着地します。一回の呼び出しで、きれいなひとまとまりを。
挿入した列に最初から書式が付いているのはなぜ?
Insert が既定で左隣の列の書式をコピーするからです(CopyOrigin:=xlFormatFromLeftOrAbove)。代わりに
右から受け継ぐには CopyOrigin:=xlFormatFromRightOrBelow を渡すか、あとから新しい列に .ClearFormats
を呼んで本当にまっさらにします。
列を挿入すると数式は壊れますか?
ワークシートの数式は壊れません — Excel が参照を書き換え、シフトをまたいでデータに追従させます。更新され
ないのは、Range("D5") のような VBA にべた書きしたアドレスです。そのリテラルは依然として D 列を指します
が、そこは今や別のセルです。挿入の前にセルを Range オブジェクトとして捕まえるか、あとから見出し名で見
つけましょう。
固定した列文字ではなく特定の見出しの前に列を挿入するには?
見出しを見つけ、その EntireColumn に対して挿入します。Rows(1).Find("Amount", LookAt:=xlWhole).EntireColumn.Insert。
これはレイアウトの変更を生き延びます。列を、今どこにあるかではなく、それが 何であるか で特定するから
です。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-09-15。
関連ガイド: VBA 列の削除 · VBA セルの挿入 · VBA 行の挿入 · VBA 列の非表示 · VBA 列の幅
