エクセルVBAでデータを並び替えたいとき、1つの条件だけでなく複数の列を組み合わせてソートしたい場面はよくあるものです。
手作業での並び替えは毎回設定が必要で手間がかかりますが、VBAを使えば複数条件のソートを一瞬で自動実行できます。
この記事では【Excel VBA】並び替え・ソートを複数条件で実行する方法(Sortオブジェクト・4つ以上・複数列にも対応)について解説していきます。
ポイントは
・SortFieldsにAddで複数キーを追加する
・Sortオブジェクトを使うことで4つ以上の条件にも対応できる
・OrderはxlAscendingまたはxlDescendingで指定する
です。
それでは詳しく見ていきましょう。
Excel VBAで複数条件ソートの基本【SortFieldsとSortオブジェクト】
VBAで並び替えを行う方法は大きく2種類あります。
一つはRangeオブジェクトのSortメソッドを直接使う方法で、もう一つはWorksheetのSortオブジェクトを使う方法です。
Sortメソッドを直接使う場合はKey1・Key2・Key3の3つまでしか条件を指定できないという制限があります。
一方、SortオブジェクトとSortFieldsコレクションを組み合わせる方法では、4つ以上の条件にも対応できるため、実務での活用の幅が大きく広がります。
まず、今回解説で使用するサンプルデータを確認しましょう。
| 行 | A列:商品名 | B列:カテゴリ | C列:産地 | D列:価格 |
|---|---|---|---|---|
| 1 | 商品名 | カテゴリ | 産地 | 価格 |
| 2 | マグロ | 魚介 | 青森 | 1200 |
| 3 | カツオ | 魚介 | 高知 | 800 |
| 4 | アボカド | 野菜 | メキシコ | 350 |
| 5 | カボチャ | 野菜 | 北海道 | 420 |
| 6 | ハラス | 魚介 | 北海道 | 980 |
| 7 | マシュマロ | 菓子 | 国内 | 200 |
| 8 | チョコ | 菓子 | ベルギー | 650 |
1行目がヘッダー、2行目以降にデータが入力されているこのサンプルを元に解説します。
SortオブジェクトとSortFieldsの関係
SortオブジェクトはWorksheetに属するオブジェクトで、シート全体のソート設定を管理しています。
SortFieldsはそのSortオブジェクトの中に含まれるコレクションで、ソートのキーとなる列と並び順をまとめて管理する役割を担っています。
基本的な使い方の流れは、SortFields.Clearで既存の設定をリセットし、SortFields.Addで条件を追加、最後にSort.Applyで実行するという3ステップになります。
Rangeの直接Sortメソッドとの違い
RangeオブジェクトのSortメソッドは記述がシンプルな反面、Key1・Key2・Key3の3つまでしか条件を指定できません。
これに対してSortオブジェクトを使う方法では、SortFields.Addを繰り返し呼び出すことで条件をいくつでも追加できます。
4列以上を対象とした複雑な並び替えが必要な場合は、最初からSortオブジェクトを使うことを習慣にしておくと後から書き直す手間が省けます。
ヘッダー行の設定に注意する
ソート時にヘッダー行を含めるかどうかの設定は、Sort.Headerプロパティで指定します。
xlYesを指定すると1行目をヘッダーとして扱い、ソートの対象から除外されます。
xlNoにすると1行目もデータとして並び替えの対象になるため、ヘッダーがある場合は必ずxlYesを指定しましょう。
【ポイント】SortFields.Clearを毎回実行する習慣をつけましょう。
前回の設定が残っていると意図しない並び替えが起きることがあります。
また、Sort.Headerの指定忘れもよくあるミスですので、セットで確認するようにしてください。
Excel VBAで2〜3条件のソートを実装する方法
まずは2つ〜3つの条件を使った並び替えの基本的な実装から確認していきましょう。
先ほどのサンプルデータを使い、「カテゴリ昇順→価格降順」という2条件でソートするコードを示します。
2条件ソートのコード例
以下がSortオブジェクトを使った2条件ソートの基本形です。
Sub SortTwoKeys()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws.Sort
.SortFields.Clear
.SortFields.Add Key:=ws.Range("B2:B8"), _
Order:=xlAscending '1キー目:カテゴリ昇順
.SortFields.Add Key:=ws.Range("D2:D8"), _
Order:=xlDescending '2キー目:価格降順
.SetRange ws.Range("A1:D8")
.Header = xlYes
.Apply
End With
End Sub
実行結果は以下の通り。

このマクロの動作を順を追って確認します。
まず「Dim ws As Worksheet」でワークシート型の変数wsを宣言し、「Set ws = ThisWorkbook.Sheets(“Sheet1”)」でSheet1をwsにセットしています。
「With ws.Sort」からのWithブロックでは、wsが持つSortオブジェクトに対してまとめて設定を行います。
「.SortFields.Clear」は前回のソート設定が残っていた場合に備えてキーをすべてリセットする処理で、必ず最初に実行するべき重要な一行です。
1つ目の「.SortFields.Add Key:=ws.Range(“B2:B8”), Order:=xlAscending」でB列(カテゴリ)を昇順の第1キーとして登録しています。
2つ目の「.SortFields.Add Key:=ws.Range(“D2:D8”), Order:=xlDescending」でD列(価格)を降順の第2キーとして登録しています。
「.SetRange ws.Range(“A1:D8”)」でソート対象のデータ全体の範囲をヘッダー行込みで指定しています。
「.Header = xlYes」で1行目をヘッダーとして扱い、ソートの対象から除外することを明示しています。
最後の「.Apply」で設定した内容を実際に適用してソートを実行します。
このマクロを実行すると、サンプルデータは以下のような状態になります。
まずB列のカテゴリが「菓子→魚介→野菜」の五十音昇順でグループ化され、菓子グループにはチョコ(650円)とマシュマロ(200円)が価格の高い順で並びます。
魚介グループはマグロ(1200円)・ハラス(980円)・カツオ(800円)の価格降順、野菜グループはカボチャ(420円)・アボカド(350円)の価格降順で並び替えられた状態になります。
SetRangeにはヘッダーを含めたデータ全体の範囲を指定することがポイントです。
3条件ソートへの拡張
3条件にするにはSortFields.Addをもう1回追加するだけです。
先ほどのコードに「産地昇順」を3つ目のキーとして加えると次のようになります。
Sub SortThreeKeys()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws.Sort
.SortFields.Clear
.SortFields.Add Key:=ws.Range("B2:B8"), _
Order:=xlAscending '1キー目:カテゴリ昇順
.SortFields.Add Key:=ws.Range("D2:D8"), _
Order:=xlDescending '2キー目:価格降順
.SortFields.Add Key:=ws.Range("C2:C8"), _
Order:=xlAscending '3キー目:産地昇順
.SetRange ws.Range("A1:D8")
.Header = xlYes
.Apply
End With
End Sub
このマクロでは2条件ソートのコードに3つ目のSortFields.Addを追加しています。
「.SortFields.Add Key:=ws.Range(“C2:C8”), Order:=xlAscending」でC列(産地)を昇順の第3キーとして登録しています。
実行されるソートの優先順位は、1つ目にAddしたB列(カテゴリ昇順)、2つ目にAddしたD列(価格降順)、3つ目にAddしたC列(産地昇順)の順になります。
つまりまずカテゴリで大きく分類し、同じカテゴリ内では価格の高い順、さらに価格も同じ場合は産地の五十音順で並び替えるという動作になります。
このマクロを実行すると、カテゴリと価格が同一のデータが存在する場合にのみ第3キーの産地が機能し、それ以外は2条件ソートと同じ並び順になります。
たとえばサンプルデータに同じカテゴリ・同じ価格の商品を追加した場合、その商品群の中だけが産地の五十音順でさらに整列された状態になります。
SortFields.Addを呼び出した順番が優先順位に直結するため、記述する順番が並び替えの結果に大きく影響する点を意識しておきましょう。
OrderをxlAscending・xlDescendingで切り替える
xlAscendingは昇順(A→Z、小→大)、xlDescendingは降順(Z→A、大→小)を意味します。
数値データの場合はxlAscendingで小さい順、xlDescendingで大きい順に並び替えられます。
文字データの場合は五十音順またはアルファベット順でソートされます。
なお、OrderプロパティはSortFields.Addの省略可能な引数で、省略するとデフォルトのxlAscending(昇順)が適用されます。
【ポイント】SortFields.Addを追加する順番が優先度の順番です。
コードを見たときに「どの列を何番目のキーにしているか」が一目でわかるよう、コメントを添えておくと後のメンテナンスが楽になります。
Excel VBAで4つ以上の条件でソートする方法
Rangeの直接Sortメソッドではキーが3つまでという制限がありますが、SortオブジェクトとSortFieldsを使えば4つ以上の条件にも対応できます。
ここでは4条件のソートを実装する具体的なコードを見ていきましょう。
4条件ソートのコード例
サンプルデータにE列「在庫数」を追加したと仮定して、4条件のソートを実装します。
Sub SortFourKeys()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws.Sort
.SortFields.Clear
.SortFields.Add Key:=ws.Range("B2:B8"), _
Order:=xlAscending '1キー目:カテゴリ昇順
.SortFields.Add Key:=ws.Range("C2:C8"), _
Order:=xlAscending '2キー目:産地昇順
.SortFields.Add Key:=ws.Range("D2:D8"), _
Order:=xlDescending '3キー目:価格降順
.SortFields.Add Key:=ws.Range("E2:E8"), _
Order:=xlAscending '4キー目:在庫数昇順
.SetRange ws.Range("A1:E8")
.Header = xlYes
.Apply
End With
End Sub
このマクロでは4つのSortFields.Addを順番に記述することで、4段階の優先順位を持つソートを実現しています。
第1キーのB列(カテゴリ昇順)で大きなグループに分類し、同じカテゴリ内ではC列(産地昇順)でさらに分類します。
カテゴリと産地が同じデータはD列(価格降順)で並び替えられ、価格まで一致する場合はE列(在庫数昇順)が最終的な並び順の決め手になります。
「.SetRange ws.Range(“A1:E8”)」でE列まで含めたデータ範囲全体をソート対象に指定している点も重要です。
新しいキー列を追加した場合はSetRangeの範囲も必ず更新するようにしましょう。
このマクロを実行すると、シート上のデータはカテゴリの五十音順を最上位として、産地・価格・在庫数の順に4段階で整列された状態になります。
たとえば「魚介・北海道」に属する商品が複数あった場合、その中では価格の高い順に並び、さらに価格が同じなら在庫数の少ない順に整列されます。
このようにSortFields.Addを繰り返すだけで、理論上は何個でもソートキーを追加できます。
Rangeの直接Sortメソッドの3条件制限に悩んでいた方は、Sortオブジェクトへの切り替えを検討してみてください。
動的にデータ範囲を取得する方法
行数が変動するデータを扱う場合、SetRangeに固定の範囲を指定していると正しくソートできないことがあります。
その場合はEndプロパティを使って動的に範囲を取得するのが実用的です。
Sub SortDynamic()
Dim ws As Worksheet
Dim lastRow As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
With ws.Sort
.SortFields.Clear
.SortFields.Add Key:=ws.Range("B2:B" & lastRow), _
Order:=xlAscending
.SortFields.Add Key:=ws.Range("D2:D" & lastRow), _
Order:=xlDescending
.SetRange ws.Range("A1:E" & lastRow)
.Header = xlYes
.Apply
End With
End Sub
このマクロの動作を詳しく見ていきます。
「Dim lastRow As Long」でLong型の変数lastRowを宣言しています。
「lastRow = ws.Cells(ws.Rows.Count, “A”).End(xlUp).Row」という記述では、まずws.Rows.CountでシートA列の最終行(通常は1048576行)を指定し、そこからEnd(xlUp)で上方向に向かってデータが入力されている最終行を探し出してRowプロパティで行番号を取得しています。
この一行によってデータが何行あっても常に正確な最終行番号がlastRowに格納されます。
「Key:=ws.Range(“B2:B” & lastRow)」のように変数lastRowを文字列結合(&)することで、データ量に応じた可変の範囲指定が実現します。
「.SetRange ws.Range(“A1:E” & lastRow)」もlastRowを使うことで、データが増えても常にすべての行を含んだ範囲でソートが実行されます。
このマクロを実行すると、データが8行であっても100行であっても、その時点でA列に入力されているすべての行を対象として自動的にソートが適用された状態になります。
途中に空白行がある場合はEnd(xlUp)がその手前の行を最終行と判定するため、データの途中に空白行を挿入しない運用ルールを徹底することも合わせて意識しておきましょう。
SortFieldTypeで文字列・数値を明示する
SortFields.AddにはオプションでSortFieldTypeを指定できます。
xlSortOnValuesは値でソートする通常の指定で、xlSortOnCellColorやxlSortOnFontColorを使えばセルの色やフォントの色を基準に並び替えることも可能です。
値でのソートが目的の大半のケースではSortFieldTypeの省略で問題ありませんが、色付きセルを優先表示したい場合などに活用できる発展的な機能として覚えておくと便利かもしれません。
【ポイント】行数が変動するデータを扱う場合は、必ずlastRowで最終行を動的に取得しましょう。
固定範囲の指定は行の増減に対応できず、追加されたデータがソートから漏れる原因になります。
Excel VBAで複数列ソートを応用する方法【実用パターン集】
ここまで基本的な複数条件ソートを解説してきました。
実務ではさらに応用的な使い方が求められることもあります。
よく使われる実用パターンをいくつか見ていきましょう。
ボタンからソートを実行するパターン
マクロをボタンに割り当てておけば、VBAの知識がない人でもワンクリックで複数条件ソートを実行できます。
シート上のフォームコントロールのボタン、またはユーザーフォームのCommandButtonにSortを実行するプロシージャを割り当てることで、誰でも使えるソートツールとして仕上げることができます。
Sub SortButton_Click()
Call SortDynamic
MsgBox "並び替えが完了しました。", vbInformation
End Sub
このマクロは非常にシンプルな構成で、2つの処理だけで成り立っています。
「Call SortDynamic」で先ほど定義した動的ソートのプロシージャSortDynamicを呼び出して実行しています。
Callキーワードは省略可能ですが、別のプロシージャを呼び出していることが明示的にわかるため、記述しておく習慣をつけると可読性が向上します。
「MsgBox “並び替えが完了しました。”, vbInformation」では情報アイコン付きのメッセージボックスを表示し、ソートが完了したことをユーザーに通知しています。
このマクロを実行すると、SortDynamicによるソートが完了した直後に「並び替えが完了しました。」というダイアログが画面に表示された状態になります。
ユーザーがOKボタンを押すとダイアログが閉じ、シート上にはソート済みのデータが整列して表示されている状態で操作に戻ることができます。
このようにソートの実行処理とユーザーへの通知処理を分離しておくと、ソートロジックを変更したいときにSortDynamic側だけ修正すれば済むため、保守性の高い設計になります。
昇順・降順をセルの値で切り替えるパターン
並び順をセルに入力した値(「昇順」「降順」など)で動的に切り替えたい場面もあります。
その場合はIfで判定してOrderの値を変数にセットする方法が便利です。
Sub SortWithSwitch()
Dim ws As Worksheet
Dim sortOrder As XlSortOrder
Set ws = ThisWorkbook.Sheets("Sheet1")
If ws.Range("G1").Value = "降順" Then
sortOrder = xlDescending
Else
sortOrder = xlAscending
End If
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
With ws.Sort
.SortFields.Clear
.SortFields.Add Key:=ws.Range("D2:D" & lastRow), _
Order:=sortOrder
.SetRange ws.Range("A1:E" & lastRow)
.Header = xlYes
.Apply
End With
End Sub
このマクロの動作を詳しく説明します。
「Dim sortOrder As XlSortOrder」でXlSortOrder型の変数sortOrderを宣言しています。
XlSortOrderはExcelが定義する列挙型で、xlAscendingとxlDescendingの2つの値を持ちます。
「If ws.Range(“G1”).Value = “降順” Then」でG1セルの値を確認し、「降順」という文字列が入力されていればsortOrderにxlDescendingをセットします。
G1セルが「降順」以外(空白や「昇順」など)の場合はElseブロックでxlAscendingがセットされます。
このようにIf分岐でOrderの値を事前に変数に格納しておくことで、SortFields.Add内の記述をすっきり保てます。
「Order:=sortOrder」と変数を渡すだけで、G1セルの値に応じた並び順が適用されるシンプルな設計です。
このマクロを実行した後の状態は、G1セルに「降順」と入力されていた場合はD列(価格)が高い順に並び替えられ、それ以外の場合はD列が低い順に並び替えられた状態になります。
G1セルの値を書き換えてマクロを再実行するだけで並び順が切り替わるため、コードを一切修正せずに昇順・降順を自在に使い分けられる便利な設計です。
ソート後に元の順番に戻すための連番列を用意する
ソートを繰り返すうちに元の順番に戻したくなることがあります。
そのような場合に備えて、データ入力時からA列などに連番(シリアルナンバー)を振っておくと便利です。
連番列を第1キーとして昇順ソートすることで、いつでも元の順番に復元できます。
【ポイント】元に戻すための連番列を最初から用意しておく設計は、実務で非常に役立ちます。
データを別の条件でソートした後でも「並び替え前の状態」に一発で戻せるため、運用の安全性が高まります。
まとめ Excel VBAで複数条件ソートを実行する方法(4つ以上・Sortオブジェクト・複数列にも対応)
Excel VBAで複数条件の並び替えを実行する方法をまとめると
・基本の流れ:SortFields.Clear → SortFields.Add(条件数分)→ SetRange → Header → Apply
・2〜3条件:SortFields.AddをOrderとあわせて繰り返し追加するだけで対応可能
・4つ以上の条件:Rangeの直接SortではなくSortオブジェクトを使うことで制限なく追加できる
・動的範囲対応:lastRowでデータ末尾を取得し、SetRangeを可変にするのが実務の定番
・応用パターン:ボタン実行・セル値による昇降切り替え・連番列による元順復元
これらの方法を組み合わせることで、ほぼすべての並び替えニーズに対応できます。
まずはSortFields.Clearを忘れずに記述することと、SortFields.Addの順番が優先度の順番であることをしっかり押さえておきましょう。
複数条件ソートをVBAで自動化することで、毎回の手作業による設定の手間がなくなり、業務効率が大きく向上します。
ぜひ今回のコードをベースに、実際のデータに合わせてカスタマイズしてみてください。


コメント