はじめに
毎回同じ表を「部署」で並べ、その部署の中では「社員番号」の順に並べる、といった作業を手動で繰り返すのは手間がかかります。Excel VBAでは、SortFieldsへ並べ替え条件を順番に登録することで、複数列の優先順位を決めた並べ替えを自動化できます。
この記事では、部署を第1キー、社員番号を第2キーにする例で、SortFields.Clear、SortFields.Add、SetRange、Applyまでの基本手順を解説します。読み終えると、複数列の優先順位をVBAコードで指定し、自分の表に合わせて昇順・降順や対象範囲を変更できるようになります。
VBA自体の位置づけやマクロとの関係から確認したい場合は、Excel VBAとは?マクロとの関係とできることをわかりやすく解説を先に確認してください。
実行前に準備するデータと条件
例では、「データ」シートのA~C列に次の表があるものとします。1行目は見出しで、A列の部署には最終データ行まで値が入っている前提です。ここではExcelの「テーブル」機能(ListObject)ではなく、通常のセル範囲を対象にします。
| 部署 | 社員番号 | 氏名 |
|---|---|---|
| 営業 | 103 | 佐藤 |
| 総務 | 102 | 鈴木 |
| 営業 | 101 | 高橋 |
| 総務 | 104 | 田中 |
| 営業 | 102 | 伊藤 |
並べ替え条件は、最初に部署を昇順、その次に社員番号を昇順とします。同じ部署の行がまとまり、その中で社員番号の小さい順に並ぶ状態が完成形です。
Excelの画面操作で複数列を並べ替える方法を確認したい場合は、Excelで並べ替える方法|昇順・降順・複数列の設定を解説を参照してください。
SortFieldsで複数列を並べ替える手順
VBAで複数列を並べ替える流れは、次の5段階です。
- 並べ替え対象の最終行を取得する
SortFields.Clearで以前の並べ替え条件を消すSortFields.Addで第1キー、第2キーの順に条件を追加するSetRangeで行全体を含む並べ替え範囲を指定する- 見出し行などの設定を行い、
Applyで並べ替えを実行する
ここで重要なのは、キー列だけでなく、1行分のデータ全体をSetRangeへ含めることです。部署列だけを対象にすると、氏名や社員番号との行の対応関係を崩す原因になります。
VBAコード全体
次のコードは、「データ」シートのA列を部署、B列を社員番号、C列を氏名として並べ替える例です。
Option Explicit
Sub SortByDepartmentAndEmployeeNo()
Dim ws As Worksheet
Dim lastRow As Long
Set ws = ThisWorkbook.Worksheets("データ")
' A列を基準に最終行を取得
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
' 見出し行しかない場合は終了
If lastRow < 2 Then Exit Sub
With ws.Sort
' 以前の並べ替え条件を消す
.SortFields.Clear
' 第1キー:部署を昇順
.SortFields.Add _
Key:=ws.Range("A2:A" & lastRow), _
SortOn:=xlSortOnValues, _
Order:=xlAscending, _
DataOption:=xlSortNormal
' 第2キー:社員番号を昇順
.SortFields.Add _
Key:=ws.Range("B2:B" & lastRow), _
SortOn:=xlSortOnValues, _
Order:=xlAscending, _
DataOption:=xlSortNormal
' 見出し行を含む表全体を並べ替える
.SetRange ws.Range("A1:C" & lastRow)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
' 並べ替えを実行
.Apply
End With
End Sub
固定範囲のA1:C100ではなく、A列の最終行からlastRowを取得しているため、行数が増減してもコードを修正しにくくて済みます。A列の途中に空欄があってもEnd(xlUp)は最後の非空セルを取得できますが、末尾側でA列が空欄の行にB列・C列のデータが残る表では、その行が範囲から漏れます。その場合は、最終データ行まで必ず値が入る列を基準にしてください。
コードのポイント
SortFields.Clearは、新しい並べ替え条件を設定する前に、以前の条件を消すために使います。続けてSortFields.Addを記述した順に、第1キー、第2キーとして条件を登録します。
Keyには並べ替え判断に使うデータ行を指定し、OrderにはxlAscendingまたはxlDescendingを指定します。SetRangeには見出し行を含む表全体を指定し、1行目が見出しならHeader = xlYesとします。
最後のApplyで、登録した条件が実際の表へ反映されます。シートをActiveSheet任せにせず、ThisWorkbook.Worksheets("データ")のように明示しておくと、別シートが選択されているときに意図しない表を並べ替える事故を防ぎやすくなります。
並べ替え結果と条件の変更
上のコードを実行すると、表は次の順になります。
| 部署 | 社員番号 | 氏名 |
|---|---|---|
| 営業 | 101 | 高橋 |
| 営業 | 102 | 伊藤 |
| 営業 | 103 | 佐藤 |
| 総務 | 102 | 鈴木 |
| 総務 | 104 | 田中 |
社員番号を大きい順にしたい場合は、第2キーのOrder:=xlAscendingをOrder:=xlDescendingへ変更します。3つ目のキーが必要なら、同じ要領でSortFields.Addをもう1つ追加します。
並べ替えキーの列を変更するときは、KeyだけでなくSetRangeにその列が含まれているかも確認してください。キー列が表の外に出ている設計は避け、並べ替え対象となる1レコード分の列をまとめて扱います。
Range.Sortとの違い
Excel VBAには、Range.SortへKey1、Key2、Key3を渡して並べ替える方法もあります。1~3個のキーを短いコードで処理したい場合には使いやすい方法です。
一方、SortFieldsは並べ替え条件を1件ずつ追加できるため、条件の追加・削除や順序をコード上で追いやすくなります。この記事では「複数列の優先順位を明示して自動化する」ことを中心にするため、SortFieldsを基本例として扱います。
注意点
見出し行があるのにHeader = xlNoとしてしまうと、見出しまでデータとして並べ替えられる可能性があります。反対に見出しがない表でxlYesを指定すると、先頭行が並べ替え対象から外れます。
また、社員番号などの数値列に「数値として保存されたセル」と「文字列として保存されたセル」が混在していると、期待した数値順にならないことがあります。並べ替え前に、同じ列のデータ形式が揃っているか確認してください。
なお、このコードは通常のセル範囲を対象にしています。Excelの「テーブル」機能(ListObject)内を並べ替える場合は、テーブル側のSortオブジェクトを使用し、SetRangeは使いません。
よくある失敗
| 症状 | 主な原因 | 確認する点 |
|---|---|---|
| 他の列との対応が崩れる | SetRangeが一部の列だけになっている | 1レコード分の全列を範囲へ含める |
| 以前の条件が残る | SortFields.Clearをしていない | 条件追加前にClearする |
| 見出しまで並べ替わる | Headerの指定が実データと合っていない | 見出しありならxlYes |
| 数字の順番がおかしい | 数値と文字列の数値が混在している | セルのデータ形式を揃える |
| 別シートが並べ替わる | RangeやSortの対象シートが曖昧 | ws.Rangeのようにシートを明示する |
| 新しい行が対象外になる | 並べ替え範囲を固定している | 最終行を取得して範囲を組み立てる |
まとめ
Excel VBAで複数列を優先順位付きで並べ替えるときは、SortFields.Clearで既存条件を消し、SortFields.Addで第1キー、第2キーの順に条件を追加します。その後、SetRangeで表全体を指定し、見出しの有無などを設定してApplyを実行します。
コードを自分の表へ合わせるときは、キー列だけを見るのではなく、並べ替え対象となる行全体、見出しの有無、各列のデータ形式まで確認することが重要です。この流れを押さえれば、毎回同じ複数条件で行う並べ替えをVBAで再現できます。