Excelで一覧データを管理していると、「特定の部署だけを一覧にしたい」「ステータスが完了になっているデータだけを取り出したい」といった作業が発生します。
フィルターを使って手作業で絞り込むこともできますが、同じ条件で定期的に抽出する業務では、絞り込みと転記を繰り返すだけでも手間がかかります。
VBAを利用すれば、指定した列の値を判定し、条件に一致した行だけを別シートへ抽出できます。
重要なのは、単純に行をコピーすることではありません。元データから必要なレコードを選別し、抽出結果として別シートに一覧を作るという流れで考えることです。
この記事では、1つの条件に完全一致する行を対象として、検索条件の管理方法や抽出先の考え方、後から修正しやすいコードの組み方まで実務を意識して解説します。
✅ VBAで条件に一致する行を別シートへ抽出する仕組み
条件に一致する行を抽出するときは、いきなりコピー処理から作り始めないことが大切です。実務で起きやすいのが、「どの列を条件判定しているのか」「どこまでを1件のデータとして抽出しているのか」が分からなくなるケースです。
また、検索条件と転記処理を1つに詰め込むと、後から条件だけを変更したい場合にもコード全体を確認する必要があります。抽出元と抽出先のシートを明示していないコードも、操作中のシートによって結果が変わる原因になります。さらに、「条件に一致する」と「特定の文字を含む」は同じ判定ではありません。まずは、今回の抽出処理をどのような流れで組み立てるのか整理しておきましょう。
・条件を判定して必要な行だけを選別する
たとえば「売上一覧」シートに次のデータがあるとします。
| A列:商品名 | B列:担当部署 | C列:売上 |
|---|---|---|
| 商品A | 東京 | 120000 |
| 商品B | 大阪 | 80000 |
| 商品C | 東京 | 150000 |
| 商品D | 名古屋 | 90000 |
| 商品E | 東京 | 110000 |
ここから、B列の担当部署が「東京」の行だけを別シートへ抽出するとします。
処理の流れは次のようになります。
- 「売上一覧」シートのデータ範囲を確認する
- B列を上から順番に判定する
- 値が「東京」と一致しているか確認する
- 一致した行のデータを抽出対象にする
- 「抽出結果」シートへ上から順番に書き出す
このように考えると、条件判定とデータ転記は別の役割であることが分かります。
今回の例ではB列だけを条件判定しますが、条件に一致した場合はA~C列を1件のデータとして抽出します。
・今回は完全一致した行を抽出する
今回の条件は、
targetValue = "東京"
として、B列の値が「東京」と完全に一致するかを判定します。
基本となる条件式は次の形です。
If sourceSheet.Cells(rowIndex, conditionColumn).Value = targetValue Then
この場合、
東京
は一致しますが、
東京営業所
東京都
東京エリア
などは一致しません。
セル内に「東京」という文字が含まれていれば対象にしたい場合は、完全一致ではなくInStrなどによる部分一致検索が必要です。
この違いを明確にしておくことで、「完全一致では抽出されないデータがある」というトラブルを防ぎやすくなります。
今回はセルの値が指定した条件と完全に一致する場合を対象にしています。セル内に特定の文字が含まれていれば抽出したい場合は、「【VBA】特定の文字を含む行を抽出する方法|InStrで部分一致検索」で、InStrを使った部分一致の判定方法を詳しく解説しています。
✅ VBAで条件に一致する行を別シートへ抽出する基本コード
条件に一致した行を別シートへ抽出するだけなら、短いVBAコードでも実現できます。しかし、シート名や条件列、検索値などを処理の各所へ直接書いてしまうと、仕様変更のたびに複数箇所を修正することになります。
実務では「東京から大阪へ条件を変えたい」「B列ではなくD列を判定したい」といった変更は珍しくありません。また、ActiveSheetや選択中のセルに依存したコードでは、実行時のExcelの状態によって結果が変わる危険があります。短さだけを優先するより、抽出元・抽出先・検索条件がコード上で明確になっている方が保守しやすくなります。ここでは、後から条件を変更しやすい形で基本的な抽出処理を作成します。
・条件に完全一致した行を抽出するコード
次のコードでは、「売上一覧」シートのB列が「東京」の行だけを「抽出結果」シートへ書き出します。
Sub ExtractMatchingRows()
Dim sourceSheet As Worksheet
Dim outputSheet As Worksheet
Dim targetValue As String
Dim conditionColumn As Long
Dim lastRow As Long
Dim lastColumn As Long
Dim outputRow As Long
Dim rowIndex As Long
Set sourceSheet = ThisWorkbook.Worksheets("売上一覧")
Set outputSheet = ThisWorkbook.Worksheets("抽出結果")
'抽出条件を設定
targetValue = "東京"
conditionColumn = 2
'元データの範囲を取得
lastRow = sourceSheet.Cells( _
sourceSheet.Rows.Count, conditionColumn).End(xlUp).Row
lastColumn = sourceSheet.Cells(1, _
sourceSheet.Columns.Count).End(xlToLeft).Column
'抽出結果は2行目から書き込む
outputRow = 2
For rowIndex = 2 To lastRow
If sourceSheet.Cells(rowIndex, conditionColumn).Value = targetValue Then
outputSheet.Cells(outputRow, 1) _
.Resize(1, lastColumn).Value = _
sourceSheet.Cells(rowIndex, 1) _
.Resize(1, lastColumn).Value
outputRow = outputRow + 1
End If
Next rowIndex
End Sub
このコードで特に分けているのが、
targetValue = "東京"
conditionColumn = 2
という抽出条件です。
検索値を変更したい場合はtargetValue、条件判定する列を変更したい場合はconditionColumnを修正できます。
ループ内部へ、
If sourceSheet.Cells(rowIndex, 2).Value = "東京" Then
と直接書く方法でも動作します。
しかし、条件が後から変更される可能性を考えると、変更対象となる値を変数として分離しておいた方が、処理の目的を把握しやすくなります。
・最終行と最終列を取得して抽出範囲を決める
今回のコードでは、条件判定する列から最終行を取得しています。
lastRow = sourceSheet.Cells( _
sourceSheet.Rows.Count, conditionColumn).End(xlUp).Row
データが500行目までなら500、3000行目までなら3000というように、データ量に合わせてループ範囲が変わります。
一方、最終列は1行目から取得しています。
lastColumn = sourceSheet.Cells(1, _
sourceSheet.Columns.Count).End(xlToLeft).Column
たとえば見出しがA~C列まで存在すれば、lastColumnには3が入ります。
これにより、
.Resize(1, lastColumn)
でA列からC列までを1件のデータとして扱えます。
行全体ではなく、実際に使用しているデータ範囲だけを転記することがポイントです。
✅ VBAで抽出した行をValueで別シートへ転記する理由
VBAで行を別シートへ移す処理を見ると、Copyメソッドを使う方法を思い浮かべることも多いでしょう。しかし、「条件に一致したデータの一覧を作る」という目的では、必ずしも行そのものをコピーする必要はありません。書式や数式まで引き継いでしまうと、抽出先で元シートと同じ見た目や計算処理が不要な場合には、かえって扱いにくくなることがあります。
また、行全体を対象にすると、必要以上に広い範囲をコピーすることにもなります。抽出結果を何に利用するのかによって、Copyと値転記を使い分けることが重要です。今回は「抽出結果としてデータ一覧を作る」という目的に合わせて、値を直接書き込む方法を採用しています。
・必要な範囲だけをまとめてValueで書き込む
条件に一致したときに実行しているのが、次の処理です。
outputSheet.Cells(outputRow, 1) _
.Resize(1, lastColumn).Value = _
sourceSheet.Cells(rowIndex, 1) _
.Resize(1, lastColumn).Value
たとえばlastColumnが3の場合、
A列:商品名
B列:担当部署
C列:売上
の3項目をまとめて抽出先へ書き込みます。
セルごとに、
outputSheet.Cells(outputRow, 1).Value = _
sourceSheet.Cells(rowIndex, 1).Value
outputSheet.Cells(outputRow, 2).Value = _
sourceSheet.Cells(rowIndex, 2).Value
outputSheet.Cells(outputRow, 3).Value = _
sourceSheet.Cells(rowIndex, 3).Value
と記述することもできますが、列が増えるほどコードも長くなります。
今回のように元データと抽出結果の列構成が同じなら、Resizeで必要範囲をまとめて扱う方が、列数が増えた場合にも対応しやすくなります。
・Copyを使う方法との役割の違い
Copyを利用すると、次のような処理も可能です。
sourceSheet.Cells(rowIndex, 1) _
.Resize(1, lastColumn).Copy _
Destination:=outputSheet.Cells(outputRow, 1)
こちらは、値以外の情報も引き継ぎたい場合に選択肢になります。
一方、今回のように、
「元データから条件に合うレコードを選別して、抽出結果の一覧を作る」
ことが目的なら、値だけを書き出した方がシンプルなケースがあります。
特に抽出結果を、
- 集計処理へ利用する
- CSVなど別形式への出力元にする
- 他のVBA処理へ渡す
- 一時的な確認用データとして利用する
といった用途で使う場合は、元シートの書式まで必要とは限りません。
また、Valueによる転記ではクリップボードを利用しないため、コピー状態を残さずに処理できます。
重要なのは、Copyを避けることではありません。
値だけが必要なのか、書式や数式を含めたコピーが必要なのかを先に決め、その目的に合った方法を選ぶことが実務では大切です。
今回は抽出結果の一覧を作ることを目的として、値を直接転記しています。条件に一致した行を書式なども含めてコピーする方法を確認したい場合は、「【VBA】条件に一致する行を別シートへコピーする方法|指定した値で行を判定」も参考にしてください。
✅ VBAで抽出結果を上から順番に並べる仕組み
条件判定そのものが正しくても、抽出先の行番号を適切に管理しなければ結果を一覧として並べられません。元データでは条件に一致する行が連続しているとは限らず、2行目・5行目・10行目だけが対象になることもあります。その元の行番号をそのまま抽出先に使うと、抽出結果にも不要な空白行が発生します。
また、outputRowを増やす位置を間違えると、条件に一致していない場合まで次の行へ進んでしまいます。抽出結果では「元データの何行目だったか」より、「何件目の抽出データか」を基準に書き込み位置を管理する必要があります。この考え方は、条件抽出だけでなくさまざまなデータ転記処理でも利用できます。
・一致したときだけoutputRowを増やす
今回のコードでは、
outputRow = 2
から抽出を開始しています。
条件に一致した場合だけ、
outputRow = outputRow + 1
を実行します。
たとえば元データの、
2行目 → 東京
3行目 → 大阪
4行目 → 名古屋
5行目 → 東京
6行目 → 大阪
7行目 → 東京
が並んでいた場合、抽出先では、
2行目 → 元データ2行目
3行目 → 元データ5行目
4行目 → 元データ7行目
と連続して配置されます。
元データの行番号とは別に抽出先の行番号を管理することで、条件に一致したデータだけの一覧を作れます。
ここで、
For rowIndex = 2 To lastRow
outputRow = outputRow + 1
のようにループするたびにoutputRowを増やしてしまうと、条件に一致しなかった分だけ抽出結果にも空白行ができます。
そのため、outputRowを更新する処理は条件に一致して転記が完了した後に置くことがポイントです。
この「元データの行番号」と「出力先の行番号」を別々に管理する考え方を理解しておくと、条件抽出のコードを別の転記処理へ応用するときにも役立ちます。
✅ VBAで見出しを含めて抽出結果を作成する方法
条件に一致するデータだけを別シートへ書き出せても、見出しがなければ「各列が何を表しているのか」が分かりにくくなります。自分だけが使用する一時的なデータなら問題にならないこともありますが、抽出結果を別の担当者へ渡したり、後から見直したりする場合には注意が必要です。
また、元データの列が追加されたとき、抽出先の見出しだけを手作業で管理していると列構成がずれる可能性もあります。実務ではデータ本体だけでなく、見出しも含めて1つの一覧として管理した方が扱いやすくなります。特に今回のように元シートと抽出先の列構成が同じ場合は、見出しも元データから取得できます。抽出処理を実行するたびに同じ構成の一覧を作れるようにしておきましょう。
・元データの見出しを抽出先へ転記する
前半のコードでは、抽出結果を2行目から書き込んでいました。
その前に、元データの1行目を抽出先へ転記します。
'見出しを抽出先へ転記
outputSheet.Cells(1, 1) _
.Resize(1, lastColumn).Value = _
sourceSheet.Cells(1, 1) _
.Resize(1, lastColumn).Value
たとえば元データが、
商品名 担当部署 売上
という構成なら、その見出しも「抽出結果」シートの1行目へ書き込まれます。
その後、
outputRow = 2
としてデータ部分を2行目から抽出すれば、
商品名 担当部署 売上
商品A 東京 120000
商品C 東京 150000
商品E 東京 110000
のような一覧を作成できます。
見出しを元データから取得する構成なら、元シート側で項目名が変更された場合にも抽出結果へ反映できます。
✅ VBAで前回の抽出結果をクリアしてから再抽出する
同じマクロを繰り返し実行する場合に注意したいのが、前回の抽出結果です。新しい結果を上から書き込むだけでは、前回より抽出件数が少なくなったときに古いデータが下側へ残る可能性があります。
たとえば前回は100件、今回は80件だった場合、81~100件目に相当する古い結果が残ってしまいます。見た目だけでは今回抽出されたデータなのか判断できず、集計や確認作業にも影響します。実務では「コードがエラーにならない」だけではなく、「繰り返し実行しても正しい結果になるか」まで考える必要があります。今回のように毎回最新の抽出一覧を作る処理では、書き込み前に前回結果をクリアしておくと安全です。
・データ部分をクリアしてから新しい結果を書き込む
抽出結果を毎回作り直す場合は、抽出処理の前に既存データを消しておきます。
たとえば、見出しを含めて毎回作り直すなら次のようにできます。
outputSheet.Cells.ClearContents
その後で、
outputSheet.Cells(1, 1) _
.Resize(1, lastColumn).Value = _
sourceSheet.Cells(1, 1) _
.Resize(1, lastColumn).Value
として見出しを書き戻します。
ただし、ClearContentsはセルの値や数式を削除する処理です。
抽出先シートに固定の説明文や別の集計データなどが存在する場合、シート全体を対象にするのは適切ではありません。
そのような場合は、抽出結果として使用している範囲だけをクリアします。
たとえば、1行目の見出しを残して2行目以降だけを更新するなら、
Dim outputLastRow As Long
outputLastRow = outputSheet.Cells( _
outputSheet.Rows.Count, 1).End(xlUp).Row
If outputLastRow >= 2 Then
outputSheet.Range( _
outputSheet.Cells(2, 1), _
outputSheet.Cells(outputLastRow, lastColumn) _
).ClearContents
End If
という方法があります。
「とりあえずシート全体を消す」のではなく、どこまでがマクロによって管理される範囲なのかを決めてからクリアすることが大切です。
・毎回作り直す抽出と既存データへの追記を区別する
今回のコードは、現在の元データを条件判定し、最新の抽出結果を毎回作り直す処理を想定しています。
一方、
昨日までの抽出結果
↓
今日条件に一致したデータを末尾へ追加
のような処理では、既存データをクリアしてはいけません。
この場合は、抽出先の最終行を取得して、その次の行から追記する設計が必要です。
つまり、
- 現在の条件一致データだけを一覧化する → 毎回作り直す
- 過去のデータを残して履歴として蓄積する → 最終行へ追加する
という違いがあります。
同じ「別シートへの転記」でも目的は異なるため、業務要件を確認してから処理方法を決めることが重要です。
今回は抽出結果を毎回作り直していますが、過去のデータを残したまま条件一致した行を末尾へ追加したいケースもあります。既存データへ追記する方法は、「【VBA】条件に一致する行をコピーして別シートの最終行へ追加する方法」で詳しく解説しています。
✅ VBAで条件に一致する行が0件だった場合も確認する
条件抽出では、必ず対象データが存在するとは限りません。ところが、マクロが正常終了しただけでは「0件だった」のか「条件指定を間違えた」のか判断しにくいことがあります。特に抽出結果を事前にクリアする設計では、対象が0件の場合に見出しだけが残るため、利用者が処理失敗と勘違いすることもあります。
また、検索条件をセル入力などへ変更した場合には、入力ミスによって1件も一致しないケースも考えられます。実務で繰り返し使用するマクロでは、処理結果を利用者が判断できる仕組みも重要です。そこで、何件抽出できたのかを数えておくと、処理後の確認がしやすくなります。
・抽出件数をカウントして0件を判定する
抽出件数を管理する変数を追加します。
Dim matchCount As Long
条件に一致した場合に、
matchCount = matchCount + 1
として件数を増やします。
ループ終了後に、
If matchCount = 0 Then
MsgBox "条件に一致するデータはありませんでした。", vbInformation
Else
MsgBox matchCount & "件のデータを抽出しました。", vbInformation
End If
とすれば、処理結果を確認できます。
抽出件数を管理しておくメリットは、メッセージを表示できることだけではありません。
後から、
0件なら後続処理を実行しない
一定件数以上なら確認を表示する
抽出件数をログへ記録する
といった処理にも発展させられます。
単純な抽出マクロでも、処理結果を数値として把握できる構成にしておくと、実務での確認や改修がしやすくなります。
✅ VBAで条件一致データを安全に抽出する実務コード
ここまでの内容をまとめると、実務で繰り返し使用する場合は、単に条件一致した行を書き出すだけでなく、前回結果の扱いや抽出件数まで考えておくと安全です。ただし、あらゆる機能を1つのコードへ追加すればよいわけではありません。必要以上に複雑にすると、条件変更や改修時に処理を追いにくくなります。
今回の目的は、1つの条件に完全一致するデータから最新の抽出一覧を作成することです。その目的に必要な処理だけを順番に配置することで、後から見ても何をしているコードなのか判断しやすくなります。最後に、ここまで解説した内容を1つにまとめたコードを確認しましょう。
・見出し・クリア・件数確認まで含めた実務コード
Sub ExtractMatchingRows()
Dim sourceSheet As Worksheet
Dim outputSheet As Worksheet
Dim targetValue As String
Dim conditionColumn As Long
Dim lastRow As Long
Dim lastColumn As Long
Dim outputLastRow As Long
Dim outputRow As Long
Dim rowIndex As Long
Dim matchCount As Long
Set sourceSheet = ThisWorkbook.Worksheets("売上一覧")
Set outputSheet = ThisWorkbook.Worksheets("抽出結果")
'抽出条件
targetValue = "東京"
conditionColumn = 2
'元データの最終行・最終列を取得
lastRow = sourceSheet.Cells( _
sourceSheet.Rows.Count, conditionColumn).End(xlUp).Row
lastColumn = sourceSheet.Cells(1, _
sourceSheet.Columns.Count).End(xlToLeft).Column
'前回の抽出結果だけをクリア
outputLastRow = outputSheet.Cells( _
outputSheet.Rows.Count, 1).End(xlUp).Row
If outputLastRow >= 2 Then
outputSheet.Range( _
outputSheet.Cells(2, 1), _
outputSheet.Cells(outputLastRow, lastColumn) _
).ClearContents
End If
'見出しを転記
outputSheet.Cells(1, 1) _
.Resize(1, lastColumn).Value = _
sourceSheet.Cells(1, 1) _
.Resize(1, lastColumn).Value
outputRow = 2
'条件に一致する行だけを抽出
For rowIndex = 2 To lastRow
If sourceSheet.Cells( _
rowIndex, conditionColumn).Value = targetValue Then
outputSheet.Cells(outputRow, 1) _
.Resize(1, lastColumn).Value = _
sourceSheet.Cells(rowIndex, 1) _
.Resize(1, lastColumn).Value
outputRow = outputRow + 1
matchCount = matchCount + 1
End If
Next rowIndex
'処理結果を通知
If matchCount = 0 Then
MsgBox "条件に一致するデータはありませんでした。", _
vbInformation
Else
MsgBox matchCount & "件のデータを抽出しました。", _
vbInformation
End If
End Sub
このコードでは、
- 元シートと抽出先シートを明示する
- 抽出条件を設定する
- 元データの範囲を取得する
- 前回の抽出結果をクリアする
- 見出しを転記する
- 条件に一致する行だけを抽出する
- 抽出件数を通知する
という順番で処理しています。
各処理の役割を分けているため、後から条件を変更するときにも確認する場所が分かりやすくなります。
また、SelectやActivateを使わず、sourceSheetとoutputSheetを明示している点も重要です。
画面上でどのシートが選択されているかに依存しないため、別の処理からこのマクロを呼び出す場合にも扱いやすくなります。
ここでは1つの条件に完全一致するデータを抽出しています。実務で「部署が東京かつ売上が10万円以上」のように複数の条件を組み合わせたい場合は、「【VBA】複数条件に一致する行を抽出する方法|AND・OR条件でデータを判定」もあわせて確認してみてください。
✅ VBAで大量データを抽出するときは配列処理も検討する
今回のコードは処理内容を追いやすく、条件抽出の基本を実務へ取り入れやすい構成ですが、データ件数が大幅に増えると別の方法が適することがあります。数百~数千件程度の処理と、数万件以上を繰り返し抽出する処理では、求められる設計が同じとは限りません。
特にワークシートのセルを1行ずつ読み取り、条件一致するたびに書き込む方法では、セルへのアクセス回数が増えていきます。ただし、データ量が少ないのに最初から複雑な配列処理へ変更すると、今度は保守性が下がる可能性があります。処理速度だけを基準にコードを複雑にするのではなく、実際のデータ量と実行頻度を確認することが大切です。必要になった段階で、ワークシート上の処理からVBA内部での処理へ切り替える考え方を持っておきましょう。
・大量データでは配列内で条件を判定する
データ量が多い場合は、
- 元データを配列へ一括で読み込む
- VBA内部で条件を判定する
- 一致したデータを出力用の配列へ格納する
- 最後に抽出結果を一括で書き込む
という方法があります。
たとえば元データの取得は、次のような考え方です。
Dim sourceData As Variant
sourceData = sourceSheet.Range( _
sourceSheet.Cells(1, 1), _
sourceSheet.Cells(lastRow, lastColumn) _
).Value
これにより、ワークシート上のセルを1件ずつ読み取るのではなく、対象範囲をVBA内部へまとめて取得できます。
その後は配列内で、
If sourceData(rowIndex, conditionColumn) = targetValue Then
のように条件を判定できます。
大量のデータを扱う業務では、ワークシートへのアクセス回数を減らすことで処理時間を改善できる場合があります。
一方、数百件程度の一覧をたまに抽出するだけなら、今回紹介したセル範囲を直接扱う方法でも十分なケースがあります。
処理速度・コードの読みやすさ・今後の保守性のバランスを見て選択することが重要です。
抽出条件が単純な完全一致ではなく、文字列の一部を含むかどうかで判定する場合は、条件式の設計も重要になります。LikeとInStrを使った条件分岐の考え方は、「【VBA】文字列の部分一致(IF文)|LikeとInStrで壊れない条件分岐を設計する」で詳しく解説しています。
✅ まとめ:VBAで条件に一致する行だけを別シートへ抽出しよう
VBAで条件に一致する行を別シートへ抽出する場合は、条件判定だけでなく、抽出結果をどのように管理するかまで考えることが大切です。単純に条件一致した行をコピーするだけでは、前回結果が残ったり、抽出件数が分からなかったりする可能性があります。
また、今回のような「最新の条件一致データ一覧」と、既存データへ履歴として追加する処理では設計も異なります。抽出元・抽出先・検索条件を明確に分けておけば、後から仕様が変わった場合にも対応しやすくなります。データ量が増えた場合には、配列を利用してVBA内部で条件判定する方法へ発展させることもできます。まずは1つの条件による抽出を安定して作り、業務内容に応じて必要な機能を追加していきましょう。
- 条件を判定する列と、抽出するデータ範囲は分けて考える
- 完全一致の場合は比較演算子でシンプルに判定できる
- 抽出結果を一覧化する場合は、見出しも転記すると分かりやすい
- 毎回最新の一覧を作るなら、前回の抽出結果を適切にクリアする
- 条件一致したときだけ出力行を増やし、空白行ができないようにする
- 抽出件数を管理すると、0件の場合や処理結果を確認しやすい
- 値だけが必要なら
Value、書式なども必要ならCopyを使い分ける - 既存データへの追記と、最新一覧の作り直しは別の処理として考える
- 大量データでは配列へ一括取得し、VBA内部で条件判定する方法も選択肢になる
条件抽出の基本を整理しておけば、「複数の条件に一致するデータだけを抽出する」「部分一致したデータを取り出す」「抽出結果を既存一覧へ追加する」といった処理にも発展できます。目的ごとに処理を分けて設計することで、似たマクロを増やすだけではなく、後から修正・再利用しやすいVBAへつなげられます。