TL;DR —
Columns("C").DeleteはInsertを逆に走らせたものです。C 列を取り除き、その右にあるす べてを一列分 左 へ引きずります。同じシフト、逆の方向 — ただし破壊的なひねりが加わります。削除された セルを参照していた数式は、もう指す先がなくなり、恒久的に#REF!に崩れ落ちます。そして 前進 ルー プの中で削除すると、列を飛ばします。削除するたびに、その後ろの列の番号が振り直されるからです。右から 左へ削除するか、対象をUnionにまとめて一度だけ削除してください。
Sub DeleteFlaggedColumns()
Dim ws As Worksheet, c As Long, kill As Range
Set ws = ThisWorkbook.Worksheets("Report")
For c = ws.UsedRange.Columns.Count To 1 Step -1 ' 走査するだけ。ループの途中では削除しない
If ws.Cells(1, c).Value = "" Then
If kill Is Nothing Then Set kill = ws.Columns(c) _
Else Set kill = Union(kill, ws.Columns(c))
End If
Next c
If Not kill Is Nothing Then kill.Delete ' 一回のシフトで済み、番号は振り直されない
End Sub
列の削除は、列の挿入 とまったく同じグリッドのシフトを使います — ただ右 へ押しやる代わりに、左へ引き寄せるだけです。Delete をより鋭い道具にしているのは、そのシフトが 破壊的 だという点です。データが去り、それを狙っていた参照が壊れます。列削除のバグはほとんど、二つの失敗モード で説明がつきます — 壊れた参照と、飛ばされた列 — そしてどちらも、シフトから直に生まれます。
この記事で学べること
- 考え方の軸 — Delete はグリッドを左へ引き寄せ、その隙間を指していた参照は死ぬ
- なぜ
#REF!が出るのか、そしてシフトを生き延びる数式と砕け散る数式の違い - 前進ループの罠 — なぜ削除ループは列を飛ばすのか、そして右から左へという直し方
- ループの途中で番号が振り直されないよう、一つの
Unionで条件削除する - 本当は
DeleteではなくClearContentsが欲しかったとき
考え方の軸:Delete は左へ引き寄せ、隙間は参照を道連れにする
Columns("C").Delete は C 列を取り除き、それから D を C の場所へ、E を D の場所へ、と順にずらしていきま
す。Excel は 生き残る 参照を調整します — =SUM(D2:D100) という数式は =SUM(C2:C100) になります。その
データが左へ移り、Excel がそれに追従したからです。ここまでは親切です。
親切でないのは、C 列 そのもの を指していた参照です。C が消えると、=C5*A5 のような数式は、何もないと
ころへはシフトできず — 着地するセルがないので — =#REF!*A5 になって壊れたままになります。#REF! は一時
的な不具合ではありません。参照が破壊された、と Excel が告げているのです。しかもそれは、あなたが見てすら
いないシートで襲ってくることがあります。三つ離れたタブの数式が、いま削除した列にこっそり依存しているか
もしれないからです。
そこから導かれるルール。ほかの数式が読んでいる列を削除する前に、それらの数式がどうなるかを決めてくだ
さい — 張り替えるか、依存する側を先に値へ変換します。列を盲目的に削除すると、マクロが「成功」したあと
で、ブック中に #REF! が散らばっているのを見つけることになりかねません。
前進ループの罠:一番多い削除のバグ
C、E、G の列を削除したいとします。とっさに思いつくのは前進ループです。
Dim c As Long
For c = 3 To 7 Step 2
ws.Columns(c).Delete ' 誤り - 間違った列を削除してしまう
Next c
何が起きるか見てみましょう。3 列目(C)を削除するとすべてが左へ引き寄せられ、元の E 列はいまや D 列に、 元の G は F になります。ループは次に 5 列目を削除しますが — それはもう E ではありません — 三巡目には、 7 列目に流れ込んできた何かを削除しています。結局、間違った列を消し、消すはずだった列を残してしまいます。 削除は、まだたどり着いていない列の番号を振り直す のです。
正しい直し方は二つあり、二つ目のほうが優れています。
' 直し方 1: 右から左へループし、先の削除が後の対象を決して動かさないようにする
For c = 7 To 3 Step -2
ws.Columns(c).Delete
Next c
' 直し方 2(推奨): Union にまとめて一度だけ削除する - 順序が問題でなくなる
Dim kill As Range
Set kill = Union(ws.Columns(3), ws.Columns(5), ws.Columns(7))
kill.Delete
これは、行を削除する ときにすでに対処している病と同じものです — そこでまさ
にこの理由から下から上へループします。ここでは軸が水平なので、右から左になります。Union のやり方は方
向そのものを回避し、しかも劇的に速くなります。一回の削除が一回のシフトと一回の再計算しか引き起こさない
のに対し、N 回の個別削除は、そのそれぞれを N 回引き起こすからです。
条件による削除:集めてから、一度だけ削除する
Union のパターンが輝くのは、ルールで列を削除するときです — 見出しが空のすべての列、タイトルがリストに
一致するすべての列、空のすべての列。守るべき規律はこうです。走査して集める、走査の中では決して削除し
ない。
Sub DeleteEmptyColumns()
Dim ws As Worksheet, c As Long, kill As Range
Set ws = ThisWorkbook.Worksheets("Data")
For c = 1 To ws.UsedRange.Columns.Count
If Application.WorksheetFunction.CountA(ws.Columns(c)) = 0 Then
If kill Is Nothing Then Set kill = ws.Columns(c) _
Else Set kill = Union(kill, ws.Columns(c))
End If
Next c
If Not kill Is Nothing Then kill.Delete
End Sub
削除がループの あとで 起きるので、走査はどの方向に回してもかまいません — まだ決めている最中に番号が振
り直されることはありません。.Delete を呼ぶ前に Not kill Is Nothing を確認しましょう。さもないと、一
致が一つもなかった場合に実行時エラー 91("Object variable not set")を投げます。
Delete と ClearContents:どちらのつもりだったかを知る
うっかり #REF! を生む最も多い原因は、データ だけを消したかったのに Delete に手を伸ばすことです。
Columns("C").Deleteは列の 構造 を取り除き、すべてを左へシフトします。そこを指していた参照は壊 れ、シートの列レイアウトが変わります。Columns("C").ClearContentsはセルを空にするだけで、何もシフトしません。C 列を読んでいた数式はい まや空白(またはゼロ)を見ますが、レイアウトは手つかずで、参照は一つも壊れません。
下流の数式、グラフ、ListObject のテーブル、あるいは名前付き範囲が、その列が 存在すること に依存して
いるなら、欲しいのは ClearContents です。Delete は、その列が本当にあってはならないときのために取って
おきます。そして列がテーブルに属しているときは、Columns(...).Delete ではなくテーブル経由で削除しましょ
う — ws.ListObjects("Sales").ListColumns("Tax").Delete です。前者はテーブル自身の構造とぶつかります。
ExcelMaster の活用
列の削除は些細に見えて、三つの罠を隠しています — 見ていないシートで #REF! に壊れる参照、自分自身の番
号を振り直して間違った列を削除するループ、そしてレイアウトが生き延びるかを決める Delete か Clear か
の選択です。
ExcelMaster には、望むことを
そのまま伝えられます — 「見出しのない列をすべて削除して、合計はそのまま保って」 — すると、一致する列を一
つの Union に集め、一回のシフトで削除して番号が振り直されないようにし、削除がどこか別の場所の数式を壊
すときには警告し、「取り除く」ではなく「空にする」つもりだったときには ClearContents を使います。ブッ
クとコードはあなたの手元に残ります。
よくある質問
VBA で列を削除するには?
Columns("C").Delete を使うと C 列を取り除けます。その右のすべての列が一つ分左へシフトします。
ThisWorkbook.Worksheets("Report").Columns("C").Delete のように修飾して、たまたまアクティブなシートに作
用しないようにします。Columns("C:E").Delete は、隣り合う 3 列を一回の呼び出しで削除します。
列を削除したあとに #REF! が出るのはなぜ?
数式が削除された列の中のセルを参照していて、その列が消えると参照は指す先を失い、恒久的に #REF! になる
からです。削除位置より 右 の列を参照していた数式は無事です — Excel がデータと一緒に左へシフトさせます。
壊れるのは、削除された範囲 の中 を指していた参照だけです。ほかのシートも確認しましょう。壊れた数式は、
削除した場所にあるとは限りません。
削除ループが列を飛ばすのはなぜ?
列を削除するとその後ろのすべての列の番号が振り直されるので、For c = 1 To n の前進ループは、すでに通り
過ぎたスロットへずれ込んできた列を素通りします。右から左へループする(For c = n To 1 Step -1)か、ある
いは — こちらのほうが良いのですが — 対象の列を Union に集めて .Delete を一度だけ呼びます。これは順序
に関係なく、一回のシフトで削除します。
複数の列を一度に削除するには?
隣り合う列なら Columns("C:E").Delete。離れた列なら Union を組み立てます — Union(Columns(3), Columns(5), Columns(7)).Delete
— こうすればすべてが一回のシフトで消えます。これは正しく(番号が振り直されない)、しかも一つずつ削除する
よりずっと速い方法です。
列に対する Delete と ClearContents の違いは?
Delete は列を取り除いて残りを左へシフトするので、参照を壊しレイアウトを変えることがあります。
ClearContents はセルを空にするだけで何もシフトせず、構造もすべての参照も無傷のまま残します。下流の何か
がその列の存在に依存しているなら、ClearContents を使いましょう。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-09-15。
関連ガイド: VBA 列の挿入 · VBA セルの挿入 · VBA 行の削除 · VBA 列の非表示 · VBA SpecialCells
