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

Excel VBA で列を削除する — #REF! エラーも列の取りこぼしもなく列を削除する

|

Excel VBA で列を削除する — #REF! エラーも列の取りこぼしもなく列を削除する

TL;DRColumns("C").DeleteInsert を逆に走らせたものです。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! に壊れる参照、自分自身の番 号を振り直して間違った列を削除するループ、そしてレイアウトが生き延びるかを決める DeleteClear か の選択です。

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