【VBA】複数条件でデータを抽出して別シートにまとめる方法(コピペOK)

VBA
スポンサーリンク
スポンサーリンク

完成イメージ(Before / After)

Before(手動フィルター)

Before(実行前)のExcel画面
A B C D
1 日付 部門 項目 金額
2 2026/03/05 営業部 交通費 15000
3 2026/03/10 総務部 備品 8000
4 2026/04/01 営業部 会議費 12000
5 2026/04/15 製造部 材料費 45000

毎回手動でフィルター設定→コピー→貼り付けを繰り返す。日付範囲の設定ミスも起きる。

After(VBAで自動抽出 → 別シートにコピー)

After(実行後)のExcel画面
A B C D
1 日付 部門 項目 金額
2 2026/04/01 営業部 会議費 12000
3 2026/04/15 製造部 材料費 45000

4月分だけが別シートに自動抽出。件数表示付きで確認もラク。

どんな場面で使う?

  • 品質管理: 検査データから不良カテゴリ別に抽出して月次品質レポートを作る
  • 経理: 売上データを部門別・期間別に抽出して月次報告シートにまとめる
  • 営業: 顧客リストから地域+ランクで絞り込んでDMリストを作る
  • どんな職種でも: 「毎月同じフィルター条件でデータを抽出して別シートにまとめている」なら、この自動化が使える

なお、特定の文字を「検索してハイライトする」のは 特定の文字を含むセルを検索してハイライト を参照。この記事では「条件で行を抽出して別シートにまとめる」に特化する。抽出後のデータに重複がある場合は 重複データを一括削除して一意のリストを作る も参考にしてほしい。

実行前の準備

シート構成を確認する

このコードは以下の2シート構成を前提としている:

「データ」シート(元データ):

A列 B列 C列 D列
日付 カテゴリ 品名 金額
2026/03/01 原材料 鋼材A 50000
2026/03/05 外注費 加工B 30000
  • 1行目はヘッダー
  • 2行目以降がデータ

「抽出結果」シート:

  • 抽出結果の貼り付け先。マクロ実行時にクリアしてから貼り付ける

バックアップを取る

抽出先シートの既存データは上書きされる。元データは変更されないが、念のためファイルのコピーを保存しておく。

Excelをマクロ有効ブック(.xlsm)で保存する

  1. 「ファイル」→「名前を付けて保存」
  2. ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
  3. 保存

手順(コピペ → 実行まで約5分)

VBE(コードを書く画面)を開く

  1. Excelで Alt + F11 を押す
  2. VBE(Visual Basic Editor)が開く

標準モジュールを挿入する

  1. VBEのメニュー →「挿入」→「標準モジュール」
  2. 白い画面(コードウィンドウ)が表示される

コードを貼り付けて実行する

  1. コードウィンドウに、下のコードをそのままコピペする
  2. Alt + F8 → マクロ名を選んで「実行」

ボタンに割り当てれば毎回Alt+F8を押さなくて済む。方法は マクロをボタン1つで実行する方法 を参照。

コード(最小版)– 1条件でフィルター+別シートにコピー


'============================================================
' ■ AutoFilterで条件抽出 → 別シートにコピー(最小版)
'   → 指定列の条件に一致するデータを抽出し、別シートに貼り付け
'============================================================
Sub FilterAndCopyMinimal()

    '--- ★書き換えポイント ---
    Dim srcSheet As String
    srcSheet = "データ"           '← 元データのシート名

    Dim destSheet As String
    destSheet = "抽出結果"        '← 抽出結果の貼り付け先シート名

    Dim filterCol As Long
    filterCol = 2                 '← フィルターする列番号(2=B列)

    Dim filterValue As String
    filterValue = "原材料"        '← 抽出条件(完全一致)
    '--- ★ここまで ---

    Dim wsSrc As Worksheet
    Set wsSrc = ThisWorkbook.Worksheets(srcSheet)

    Dim wsDest As Worksheet
    Set wsDest = ThisWorkbook.Worksheets(destSheet)

    '--- 抽出先シートをクリア
    wsDest.Cells.Clear

    '--- 既存のAutoFilterを解除
    If wsSrc.AutoFilterMode Then wsSrc.AutoFilterMode = False

    '--- AutoFilter実行
    Dim lastRow As Long
    lastRow = wsSrc.Cells(wsSrc.Rows.Count, 1).End(xlUp).Row

    Dim dataRange As Range
    Set dataRange = wsSrc.Range("A1:D" & lastRow)

    dataRange.AutoFilter Field:=filterCol, Criteria1:=filterValue

    '--- 抽出結果を別シートにコピー
    Dim visibleCount As Long
    On Error Resume Next
    visibleCount = dataRange.Columns(1).SpecialCells(xlCellTypeVisible).Count - 1
    On Error GoTo 0

    If visibleCount > 0 Then
        dataRange.SpecialCells(xlCellTypeVisible).Copy
        wsDest.Range("A1").PasteSpecial xlPasteValues
        Application.CutCopyMode = False
    End If

    '--- フィルター解除
    wsSrc.AutoFilterMode = False

    '--- 完了メッセージ
    If visibleCount > 0 Then
        MsgBox visibleCount & " 件のデータを抽出しました。" & vbCrLf & _
               "結果: " & destSheet & "シート", vbInformation
    Else
        MsgBox "条件に一致するデータがありませんでした。", vbExclamation
    End If

End Sub

書き換えポイント

変数 説明 初期値
srcSheet 元データのシート名 "データ"
destSheet 抽出結果の貼り付け先 "抽出結果"
filterCol フィルターする列番号 2(B列)
filterValue 抽出条件 "原材料"

コードの流れ

  1. 抽出先シートをクリア(前回の結果を消す)
  2. 既存のAutoFilterを解除(二重設定防止)
  3. データ範囲に AutoFilter を実行
  4. SpecialCells(xlCellTypeVisible) でフィルター結果(可視セル)を取得
  5. 抽出結果を別シートにコピー(値のみ)
  6. フィルターを解除して元に戻す

重要: フィルター結果が0件の場合、SpecialCells がエラーになる。On Error Resume Next で回避し、0件チェックを行っている。転記の技術は セルの転記を自動化する方法 と同じ仕組み。

コード(実務版)– 複数条件+日付範囲+件数表示

実務では「カテゴリがAまたはB」かつ「日付が今月分」のように複数条件を組み合わせる。日付範囲のフィルターと、OR条件の指定方法を追加した版。

日付範囲の絞り込みを追加してからは、月次報告書の抽出が正確になった。先月分と今月分を間違えて報告する事故がなくなった。条件を変数で管理しているので、来月の報告でも変数を1行書き換えるだけで対応できる。


'============================================================
' ■ 複数条件AutoFilter+日付範囲+別シートコピー(実務版)
'   → カテゴリOR条件 + 日付範囲AND条件
'============================================================
Sub FilterAndCopyAdvanced()

    '--- ★書き換えポイント ---
    Dim srcSheet As String
    srcSheet = "データ"

    Dim destSheet As String
    destSheet = "抽出結果"

    '--- フィルター条件1: カテゴリ(B列)のOR条件
    Dim categoryCol As Long
    categoryCol = 2                '← カテゴリ列(B列)

    Dim categories As Variant
    categories = Array("原材料", "外注費")  '← 抽出するカテゴリ(複数可)

    '--- フィルター条件2: 日付範囲(A列)
    Dim dateCol As Long
    dateCol = 1                    '← 日付列(A列)

    Dim startDate As Date
    startDate = DateSerial(Year(Date), Month(Date), 1)  '← 今月1日

    Dim endDate As Date
    endDate = DateSerial(Year(Date), Month(Date) + 1, 0)  '← 今月末日
    '--- ★ここまで ---

    Dim wsSrc As Worksheet
    Set wsSrc = ThisWorkbook.Worksheets(srcSheet)

    Dim wsDest As Worksheet
    Set wsDest = ThisWorkbook.Worksheets(destSheet)

    '--- 抽出先シートをクリア
    wsDest.Cells.Clear

    '--- 既存のAutoFilterを解除
    If wsSrc.AutoFilterMode Then wsSrc.AutoFilterMode = False

    '--- データ範囲を設定
    Dim lastRow As Long
    lastRow = wsSrc.Cells(wsSrc.Rows.Count, 1).End(xlUp).Row

    Dim lastCol As Long
    lastCol = wsSrc.Cells(1, wsSrc.Columns.Count).End(xlToLeft).Column

    Dim dataRange As Range
    Set dataRange = wsSrc.Range(wsSrc.Cells(1, 1), wsSrc.Cells(lastRow, lastCol))

    '--- AutoFilter: カテゴリ(OR条件)
    dataRange.AutoFilter Field:=categoryCol, _
        Criteria1:=categories, _
        Operator:=xlFilterValues

    '--- AutoFilter: 日付範囲(AND条件)
    dataRange.AutoFilter Field:=dateCol, _
        Criteria1:=">=" & Format(startDate, "yyyy/MM/dd"), _
        Operator:=xlAnd, _
        Criteria2:="<=" & Format(endDate, "yyyy/MM/dd")

    '--- 抽出結果を別シートにコピー
    Dim visibleCount As Long
    On Error Resume Next
    visibleCount = dataRange.Columns(1).SpecialCells(xlCellTypeVisible).Count - 1
    On Error GoTo 0

    If visibleCount > 0 Then
        dataRange.SpecialCells(xlCellTypeVisible).Copy
        wsDest.Range("A1").PasteSpecial xlPasteValues
        Application.CutCopyMode = False
    End If

    '--- フィルター解除
    wsSrc.AutoFilterMode = False

    '--- 完了メッセージ
    Dim msg As String
    If visibleCount > 0 Then
        msg = visibleCount & " 件のデータを抽出しました。" & vbCrLf & _
              "条件: " & Join(categories, ", ") & vbCrLf & _
              "期間: " & Format(startDate, "yyyy/MM/dd") & " 〜 " & _
              Format(endDate, "yyyy/MM/dd") & vbCrLf & _
              "結果: " & destSheet & "シート"
        MsgBox msg, vbInformation
    Else
        MsgBox "条件に一致するデータがありませんでした。" & vbCrLf & _
               "条件: " & Join(categories, ", ") & vbCrLf & _
               "期間: " & Format(startDate, "yyyy/MM/dd") & " 〜 " & _
               Format(endDate, "yyyy/MM/dd"), vbExclamation
    End If

End Sub

書き換えポイント

変数 説明 初期値
srcSheet / destSheet 元データ / 抽出先シート名 "データ" / "抽出結果"
categoryCol カテゴリ列の番号 2(B列)
categories 抽出するカテゴリ(複数指定可) Array("原材料", "外注費")
dateCol 日付列の番号 1(A列)
startDate / endDate 日付範囲 今月1日〜今月末日

コードの流れ

  1. 抽出先クリア: 前回の結果を消す
  2. AutoFilter解除: 二重設定を防止
  3. カテゴリOR条件: Operator:=xlFilterValues + Array() で複数値を指定
  4. 日付AND条件: >=開始日 AND <=終了日 で範囲指定
  5. 可視セルコピー: SpecialCells(xlCellTypeVisible) で抽出結果を取得
  6. フィルター解除: 元データを元の状態に戻す
  7. 件数表示: 抽出件数・条件・期間をまとめて表示

抽出マクロをボタン(マクロをボタン1つで実行する方法)に割り当てれば、毎月の報告書作成がボタン1つで完了する。

---

よくある落とし穴5選

1. フィルター結果が0件で「SpecialCells」エラー

自分もこれで止まった。条件に一致するデータが0件のときに SpecialCells(xlCellTypeVisible) がエラーを出す。「データがないだけなのに止まるの?」と最初は戸惑った。

対策: On Error Resume Next で一旦エラーを無視し、可視セル数をカウントして0件チェックを行う。コード内で対策済み。

2. AutoFilterが二重にかかってエラー

原因: 既にAutoFilterがかかっている状態で AutoFilter を実行すると、意図しない動作になる。

対策: If wsSrc.AutoFilterMode Then wsSrc.AutoFilterMode = False で事前に解除。コード内で対策済み。

3. 日付のフィルターが効かない

原因: セルの書式が「文字列」になっていると、日付として認識されない。

自分もこれに気づくのに時間がかかった。日付に見えるのに抽出結果が0件。調べたらセルの書式が「文字列」で、Excelが日付として認識していなかった。データを入力し直すか、CDate で変換する必要がある。

対策: 日付列のセル書式を「日付」に変更する。Format(startDate, "yyyy/MM/dd") の形式がシートの日付形式と一致しているか確認する。

4. 抽出先シートの既存データが残っている

原因: 前回の抽出結果が残ったままで、新しい結果と混在する。

対策: コード冒頭で wsDest.Cells.Clear を実行して全クリアしている。

5. ワイルドカードの意図しないマッチ

原因: Criteria1:="材*" のように * を使うと、「材料」「材質」「材木」すべてにマッチする。

対策: 完全一致で抽出したい場合は * を使わない。部分一致なら "*材*" のように両側に付ける。

VBAのAutoFilterで抽出結果が0件になるときの対処法

「条件に合うデータがあるはずなのに抽出結果が空になる」という場合、原因はフィルター対象の列番号がずれていることだ。AutoFilter Field:=2 の数値はデータ範囲内の相対的な列番号であり、シートの列番号とは異なる場合がある。データ範囲の何列目を対象にしているかを確認すれば解決する。

VBAで抽出結果を別シートにコピーできないときの対処法

「SpecialCellsでエラーが出る」という場合、原因はフィルター後の表示行が0件(ヘッダーのみ)であることだ。SpecialCells(xlCellTypeVisible) は表示行がない場合にエラーになる。コピー前に Application.WorksheetFunction.Subtotal(103, 対象列) で表示行数をチェックし、0件ならスキップする分岐を入れれば安全に動作する。

---

FAQ

Q1: 3列以上に条件を設定したい

AutoFilter を列ごとに複数回実行する。条件は上書きではなくANDで積み重なる:


dataRange.AutoFilter Field:=1, Criteria1:=">=2026/03/01"   '← A列
dataRange.AutoFilter Field:=2, Criteria1:="原材料"          '← B列
dataRange.AutoFilter Field:=4, Criteria1:=">=10000"         '← D列

Q2: フィルターだけかけて、コピーはしない

別シートコピーの処理を削除し、フィルターだけ残す。手動で確認してからコピーしたい場合に便利。

Q3: 書式もコピーしたい

xlPasteValuesxlPasteAll に変更する:


wsDest.Range("A1").PasteSpecial xlPasteAll

Q4: 抽出結果をPDFで保存したい

抽出結果シートをPDFに変換できる。ExcelファイルをPDFに一括変換 を参照。

Q5: 抽出結果をCSVで出力したい

抽出結果シートをCSVに書き出せる。ExcelデータをCSVファイルに書き出す を参照。

---

まとめ

  • AutoFilter で条件指定してデータを抽出できる(最小版)
  • xlFilterValues + Array() で複数条件のOR抽出ができる(実務版)
  • 日付範囲は >= / <= のAND条件で指定する
  • 0件チェック(SpecialCells のエラー回避)を忘れずに入れる

関連記事

---

次にやりたくなること

---

コメント

タイトルとURLをコピーしました