Excel VBAで列を操作するとき、最初に出てくるのが Columns です。列の幅変更や表示・非表示、コピー、書式の適用など、列に関する処理のほとんどは Columns を起点に書けます。
ただ、実務では「Columns(1) と Columns("A") の違いが曖昧」「複数列の指定がうまくいかない」「最終列の取得がブレる」といったつまずきが多発します。さらに、ActiveSheet 依存の書き方をすると、シートが切り替わった瞬間に意図しない列を操作してしまい、事故につながりがちです。
この記事では、Columns の基本から、数字・文字列・変数での指定、複数列の安全な指定方法、そして実務で必須の「最終列取得」までを、壊れにくい設計でまとめます。
目次
- ✅ Columnsの基本|「どの列の集合」を指しているかがすべて
- ・Columnsとは何か(Rangeの集合としての列)
- ✅ 1列指定のパターン|文字列・数字・変数の使い分け
- ・文字列で指定:Columns("A")
- ・数字で指定:Columns(3)
- ・変数で指定:Columns(colIndex)
- ✅ 複数列の指定方法|Rangeでまとめるのが安全
- ・連続した複数列(A~C)を指定する
- ・非連続の複数列(A列とC列など)を指定する
- ✅ 列記号 ↔ 列番号の変換|設計の自由度が一気に上がる
- ・列番号 → 列記号に変換する
- ・列記号 → 列番号に変換する
- ✅ 最終列の取得|「UsedRange頼り」はズレるので避ける
- ・基準行の最終列を取得する(最も安定)
- ・最終列の列記号(A, B, …)も欲しい場合
- ✅ 最終列を使って処理を回す|列ループの基本設計
- ・最終列まで見出しを太字にする例
- ✅ 実務でよくある落とし穴|Columnsの「親」を間違える
- ・ActiveSheetに依存してしまう
- ・複数ブックが開いているとThisWorkbook/ActiveWorkbookがズレる
- ✅ 応用:Columnsを「設計要素」として扱うと壊れにくい
- ✅ まとめ:Columnsは「指定の仕方」と「最終列」が肝
✅ Columnsの基本|「どの列の集合」を指しているかがすべて
Columns は「列」を表すオブジェクトですが、重要なのは どの親オブジェクトにぶら下がっているか です。
よくある失敗は、Columns("A") を書いたつもりが、アクティブシートのA列を触ってしまうケースです。Excelを触りながらマクロを動かす実務では、アクティブ状態は簡単に変わります。
つまり、Columns は「列を指定する」より先に「どのシート(or 範囲)の列か」を固定しないと後で困ります。
この章で、Columns の解釈ルールを整理しておくと、以降の複数列指定や最終列取得も安定します。
結論としては、シートを明示して Worksheets("…").Columns と書くのが基本です。
・Columnsとは何か(Rangeの集合としての列)
Columns は Range と同じ系統で、列単位の範囲を返します。
Worksheets("Sheet1").Columns("A")→ A列全体(A:A)Worksheets("Sheet1").Columns(1)→ 1列目全体(A:A)
操作手順(基本の書き方)
- 操作対象のシートを変数で持つ(または直接指定)
シート.Columns(列指定)で列を得る- 列に対して幅や書式などを操作する
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)を指定する
操作手順
- シートを明示する
Range("A:C")のように列範囲で指定- 一括で書式・幅・非表示などを操作
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)
End(xlToLeft)で最終列まで戻る.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列目から最終列までループ
.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 はシンプルに見えて、実務では事故の起点になりやすい要素です。
だからこそ、最初に「シート固定」「列指定の統一」「最終列の定義」を押さえておくと、後の自動化が一気にラクになります。