VBAで自動化 VBA一覧 最終行・最終列 配列・データ操作

【VBA】Columnsの使い方完全ガイド|複数列指定・変数指定・最終列取得まで

Excel VBAで列を操作するとき、最初に出てくるのが Columns です。列の幅変更や表示・非表示、コピー、書式の適用など、列に関する処理のほとんどは Columns を起点に書けます。
ただ、実務では「Columns(1)Columns("A") の違いが曖昧」「複数列の指定がうまくいかない」「最終列の取得がブレる」といったつまずきが多発します。さらに、ActiveSheet 依存の書き方をすると、シートが切り替わった瞬間に意図しない列を操作してしまい、事故につながりがちです。
この記事では、Columns の基本から、数字・文字列・変数での指定、複数列の安全な指定方法、そして実務で必須の「最終列取得」までを、壊れにくい設計でまとめます。

✅ Columnsの基本|「どの列の集合」を指しているかがすべて

Columns は「列」を表すオブジェクトですが、重要なのは どの親オブジェクトにぶら下がっているか です。
よくある失敗は、Columns("A") を書いたつもりが、アクティブシートのA列を触ってしまうケースです。Excelを触りながらマクロを動かす実務では、アクティブ状態は簡単に変わります。
つまり、Columns は「列を指定する」より先に「どのシート(or 範囲)の列か」を固定しないと後で困ります。
この章で、Columns の解釈ルールを整理しておくと、以降の複数列指定や最終列取得も安定します。
結論としては、シートを明示して Worksheets("…").Columns と書くのが基本です。

・Columnsとは何か(Rangeの集合としての列)

ColumnsRange と同じ系統で、列単位の範囲を返します。

  • Worksheets("Sheet1").Columns("A") → A列全体(A:A)
  • Worksheets("Sheet1").Columns(1) → 1列目全体(A:A)

操作手順(基本の書き方)

  1. 操作対象のシートを変数で持つ(または直接指定)
  2. シート.Columns(列指定) で列を得る
  3. 列に対して幅や書式などを操作する
Option Explicit

Public Sub Sample_ColumnsBasic()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    
    ' A列の幅を調整
    ws.Columns("A").ColumnWidth = 20
    
    ' 1列目(A列)を非表示
    ws.Columns(1).Hidden = True
End Sub

なぜこの書き方か
ThisWorkbook.Worksheets("Sheet1") と明示することで、アクティブシート依存を排除できます。別案として ActiveSheet.Columns もありますが、操作中にシートが切り替わると対象がズレやすく、実務では避けた方が安全です。


✅ 1列指定のパターン|文字列・数字・変数の使い分け

列指定は大きく3パターンです。どれも使えますが、用途と「読みやすさ」で選ぶと壊れにくいです。
ここを曖昧にすると、複数列指定や最終列取得を組み合わせたときに「どっちの形式で返るのか」が混乱の元になります。
また、列番号(数字)と列記号(A,B,C…)を変換する場面も多いので、変換関数の考え方も合わせて押さえておくと後で困りません。
まずはそれぞれの特徴を整理します。

・文字列で指定:Columns("A")

  • 可読性が高い(A列、と直感的)
  • “列記号” が分かっている処理に向く
Public Sub Sample_ColumnByLetter()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    
    ws.Columns("C").Interior.ColorIndex = 6   ' C列を黄色(例)
End Sub

・数字で指定:Columns(3)

  • 列番号で処理したいときに便利(ループに強い)
  • 列の追加・削除で列記号がズレても追随しやすい
Public Sub Sample_ColumnByIndex()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    
    ws.Columns(3).Interior.ColorIndex = 6     ' 3列目(C列)
End Sub

・変数で指定:Columns(colIndex)

  • 実務では最頻出(最終列や、条件で変わる列に対応)
  • “数値で持つ”のが基本(扱いやすい)
Public Sub Sample_ColumnByVariable()
    Dim ws As Worksheet
    Dim colIndex As Long
    
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    colIndex = 5 ' E列
    
    ws.Columns(colIndex).Font.Bold = True
End Sub

なぜ列番号(数値)で持つのか
列番号はループや最終列計算と相性が良く、列記号への変換も可能です。列記号で持つ案もありますが、比較・加算がしづらく、拡張しにくいことが多いです。


✅ 複数列の指定方法|Rangeでまとめるのが安全

複数列を指定したいとき、ありがちな失敗は Columns("A:C")Range("A:C") の違いを曖昧にしたまま書いてしまうことです。
結論としては、「複数列=Rangeでまとめる」のが分かりやすく、保守性が高いです。
Columns("A:C") でも動きますが、他の処理(セル範囲との連結)と混ざると読みづらくなりやすいので、実務では Range を推奨します。
また、非連続列(A列とC列など)もよく出ます。ここは指定方法が少し変わるので、事故りやすいポイントです。

・連続した複数列(A~C)を指定する

操作手順

  1. シートを明示する
  2. Range("A:C") のように列範囲で指定
  3. 一括で書式・幅・非表示などを操作
Public Sub Sample_MultiColumns_Continuous()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    
    ws.Range("A:C").ColumnWidth = 15
End Sub

別案(Columnsで指定)

Public Sub Sample_MultiColumns_Continuous_Columns()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    
    ws.Columns("A:C").ColumnWidth = 15
End Sub

どちらが良いか

  • 列だけを扱うなら Columns("A:C") もOK
  • 他の範囲指定と混在する実務では Range("A:C") の方が読みやすいことが多い
    記事内では「迷いにくさ」を優先して Range で統一するのが安全です。

・非連続の複数列(A列とC列など)を指定する

Public Sub Sample_MultiColumns_NonContiguous()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    
    ws.Range("A:A,C:C").Hidden = True
End Sub

注意点
非連続範囲に対して一部の操作(並べ替え・一括貼り付け等)は制限が出ることがあります。実務では「隠す」「書式をそろえる」などの用途が多いですが、複雑な操作は列ごとに分けた方が安定します。


✅ 列記号 ↔ 列番号の変換|設計の自由度が一気に上がる

最終列取得を扱う前に、列番号と列記号の変換を押さえておくと、コードの見通しが良くなります。
実務では「列番号で計算し、ログやメッセージでは列記号で見せる」など、両方必要になる場面が多いです。
ここができると、変数指定・ループ・最終列取得の設計が一段ラクになります。

・列番号 → 列記号に変換する

Public Function ColumnLetter(ByVal colIndex As Long) As String
    ColumnLetter = Split(Cells(1, colIndex).Address(False, False), "$")(0)
End Function

使用例

Public Sub Sample_ColumnIndexToLetter()
    Dim ws As Worksheet
    Dim colIndex As Long
    
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    colIndex = 28 ' AB
    
    Debug.Print ColumnLetter(colIndex) ' "AB"
End Sub

・列記号 → 列番号に変換する

Public Function ColumnIndex(ByVal colLetter As String) As Long
    ColumnIndex = ThisWorkbook.Worksheets(1).Range(colLetter & "1").Column
End Function

なぜ関数にするのか
変換ロジックが散らばると保守性が下がります。共通関数にしておくと、後から仕様変更(対象シート切替等)が入っても直しやすいです。


✅ 最終列の取得|「UsedRange頼り」はズレるので避ける

最終列取得は、実務で最も事故が多いテーマです。
「最終列」という言葉が曖昧で、実は次のように複数の意味があります。

  • 値が入っている最終列
  • 書式だけ付いている最終列
  • フィルターや数式の残骸がある最終列
  • ヘッダー行 기준の最終列

ここを定義せずに UsedRange.Columns.Count を使うと、過去に書式が付いた列まで拾ってズレることがよくあります。
この章では、実務でよく使う「基準行(例:1行目)で最終列を決める」方式を中心に紹介します。

・基準行の最終列を取得する(最も安定)

操作手順

  1. 基準にする行を決める(例:ヘッダー行=1)
  2. End(xlToLeft) で最終列まで戻る
  3. .Column で列番号を得る
Public Function LastColByRow(ByVal ws As Worksheet, ByVal headerRow As Long) As Long
    Dim lastCol As Long
    
    lastCol = ws.Cells(headerRow, ws.Columns.Count).End(xlToLeft).Column
    LastColByRow = lastCol
End Function

使用例

Public Sub Sample_LastColByHeader()
    Dim ws As Worksheet
    Dim lastCol As Long
    
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    lastCol = LastColByRow(ws, 1)
    
    Debug.Print lastCol
End Sub

なぜこの書き方か
ヘッダー行は「列構造」を表すことが多く、データの欠損(途中の空白)にも強いです。別案として「データ行の最終列」を見る方法もありますが、行ごとにブレやすいので、列構造の取得にはヘッダー基準が安定します。

・最終列の列記号(A, B, …)も欲しい場合

Public Sub Sample_LastColLetter()
    Dim ws As Worksheet
    Dim lastCol As Long
    Dim lastLetter As String
    
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    lastCol = LastColByRow(ws, 1)
    lastLetter = ColumnLetter(lastCol)
    
    Debug.Print lastLetter
End Sub

UsedRange がズレると言われる理由は、
プロパティ自体が悪いのではなく、性質を理解しないまま使われていることにあります。
最終行・最終列をどのような基準で返すのかを把握しておくと、
「使っていい場面/避けるべき場面」が判断できるようになります。
【VBA】UsedRangeプロパティ:最終行と最終列数


✅ 最終列を使って処理を回す|列ループの基本設計

最終列が取れたら、実務では「最終列まで列を処理する」ことが多いです。
ここでのポイントは、Select を使わずに、対象のシートを固定し、列番号で回すことです。
こうすることで、処理中に画面操作が入っても壊れにくく、速度も安定します。

・最終列まで見出しを太字にする例

操作手順

  1. ヘッダー行の最終列を取得
  2. 1列目から最終列までループ
  3. .Font.Bold を適用
Public Sub Sample_LoopColumnsToLast()
    Dim ws As Worksheet
    Dim lastCol As Long
    Dim colIndex As Long
    
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    lastCol = LastColByRow(ws, 1)
    
    For colIndex = 1 To lastCol
        ws.Cells(1, colIndex).Font.Bold = True
    Next colIndex
End Sub

実務で気をつけるポイント

  • 大量データでは、セルを1つずつ触ると遅くなります。まとめて範囲指定できるなら範囲で処理します。
  • 例:ws.Range(ws.Cells(1, 1), ws.Cells(1, lastCol)).Font.Bold = True

✅ 実務でよくある落とし穴|Columnsの「親」を間違える

最後に、Columns で最も多い落とし穴を整理します。
この部分を理解していないと、コードが「たまに壊れる」状態になります。

・ActiveSheetに依存してしまう

悪い例

Public Sub Bad_ActiveSheetColumns()
    Columns("A").Hidden = True
End Sub

改善例

Public Sub Good_SpecifiedSheetColumns()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    
    ws.Columns("A").Hidden = True
End Sub

・複数ブックが開いているとThisWorkbook/ActiveWorkbookがズレる

  • ThisWorkbook:このコードが入っているブック
  • ActiveWorkbook:今アクティブなブック

実務では、マクロブックと作業ブックが分かれていることも多いので、操作対象ブックも含めて明示するのが安全です。

Columnsの「親」を間違える原因の多くは、
無意識に ActiveSheet や Selection に依存した書き方 をしてしまうことにあります。
これは Columns に限らず、VBA全体でトラブルを生みやすい設計です。
Selection をどう扱うべきかを整理しておくと、
「たまに壊れるマクロ」から抜け出せます。
【VBA】Selectionは使うべき?使わないべき?正しい考え方と実務判断


✅ 応用:Columnsを「設計要素」として扱うと壊れにくい

Columns をその場の操作で終わらせず、設計として整理すると、保守性が上がります。

  • 列番号は定数・Enumで管理する
  • ヘッダー行を基準に最終列を取得する
  • シート参照を固定して Active 依存を排除する

この設計にしておくと、列の追加・削除が入っても、影響範囲を最小化できます。


 

✅ まとめ:Columnsは「指定の仕方」と「最終列」が肝

  • Columns は親(シート)を明示しないと事故りやすい
  • 1列指定は文字列・数字・変数で使い分ける
  • 複数列指定は Range("A:C") の方が読みやすく安定しやすい
  • 最終列は「どの定義か」を決め、ヘッダー行基準が実務で安定
  • 列番号↔列記号の変換を関数化すると拡張しやすい

Columns はシンプルに見えて、実務では事故の起点になりやすい要素です。
だからこそ、最初に「シート固定」「列指定の統一」「最終列の定義」を押さえておくと、後の自動化が一気にラクになります。

    -VBAで自動化, VBA一覧, 最終行・最終列, 配列・データ操作