🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA で Advanced Filter を使う — 一意な値を抽出し、新しい範囲へフィルターする(ループなしで)

|

Excel VBA で Advanced Filter を使う — 一意な値を抽出し、新しい範囲へフィルターする(ループなしで)

TL;DRRange.AdvancedFilter は、ビューではなく データ を手渡す唯一のフィルターです。 1 回の呼び出しで、一意なリスト条件に一致した行の集合 を、ループなしで、何も削除 せずに別の場所へコピーできます。これを解き放つ考えが 2 つあります。第一に、ActionxlFilterInPlace(AutoFilter のように行を隠す)と xlFilterCopy(結果を CopyToRange に コピーする — 強力なモード)を選び分けます。第二に、その「WHERE 句」はコードではありません — 条件範囲、つまり見出しが 元の見出しと正確に一致しなければならない 小さなセルのブロック です。Unique:=True を添えれば、元をそのままに、一意なリストが 1 行で手に入ります。

' B 列から Region の値の重複なしリストを E 列へ抽出する。非破壊的。
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Sales")
ws.Range("B1:B1000").AdvancedFilter _
        Action:=xlFilterCopy, _
        CopyToRange:=ws.Range("E1"), _   ' E1 は B1 と同じ見出しを持つこと
        Unique:=True                     ' 各値を 1 つずつ、元は変更なし

AdvancedFilter は、人が最後に手を伸ばすのに、本当は最初に手を伸ばすべき道具です。結果を データとして 必要とするとき — 重複のないリスト、条件に一致する行のエクスポート、元をそのまま 残す重複除去済みのコピー — 本能は IfDictionary を伴う For Each ループを書かせます。 Excel にはまさにこのためのクエリエンジンがすでにあります。本記事は、それを定義づける 2 つの 考え — 隠す代わりにコピーできる、そして条件はセルの中に置かれる — を軸に組み立てられて います。

この記事で学べること

  • 考え方の軸 — 範囲のための簡易 SQL。ただ見るのではなく抽出する
  • その場か、コピーか — xlFilterInPlacexlFilterCopy
  • 条件範囲 — WHERE 句はコードではなくセルの中に置かれる
  • Unique:=True — 何も削除せずに重複のないリストを作る
  • 空の出力を返す、見出し不一致の罠
  • AdvancedFilterAutoFilterRemoveDuplicates

考え方の軸:範囲のための簡易 SQL

AdvancedFilter を、範囲に取り付けられた小さなクエリエンジンだと考えてください。AutoFilter は 「どの行を 見たい か?」に答え、残りをその場で隠します。AdvancedFilter はもっと大きな問いに 答えます — 「一致する行をくれ、どこかに置いて使える 新しいデータの集合 として」。その場で フィルターすることもできますが、その存在理由はコピーモードです — 元の範囲、任意の条件の組、 そして一致した(あるいは一意な)行を、選んだ宛先へ書き出します。

この捉え直しが大事なのは、ループのまるごと 1 カテゴリを置き換えるからです。「一意な顧客を取得 する」「1000 を超えるすべての注文をレポートシートに引き出す」「重複のない商品コードを列挙する」 — これらは反復ではなく、1 回の呼び出しでの抽出です。このイメージ — AdvancedFilter はデータを生み、 AutoFilter はビューを生む — を頭に置いておけば、どちらがそのタスクに必要かが分かります。

その場か、コピーか:xlFilterInPlace と xlFilterCopy

Action 引数が分かれ道です。

  • xlFilterInPlace は、AutoFilter とまったく同じように、一致しない行を元の範囲の中でその場で 隠します。データは動きません。フィルターされたビューが得られます。あとでそれをクリアするには ws.ShowAllData を呼びます。
  • xlFilterCopy は元をそのままにして、一致する行を CopyToRangeコピーします。これが AdvancedFilter を特別にするモードです — 非破壊的で、独立した使えるデータのブロックを生みます。
' コピーモード - たいていはこれが欲しい。
ws.Range("A1").CurrentRegion.AdvancedFilter _
        Action:=xlFilterCopy, _
        CriteriaRange:=ws.Range("H1:H2"), _   ' WHERE 句(後述)
        CopyToRange:=ws.Range("K1"), _        ' 結果が着地する場所
        Unique:=False

xlFilterCopy を渡すなら CopyToRange必ず 与えます。xlFilterInPlace を渡すなら 与えてはいけません(取り違えるとどちらの場合も Excel はエラーになります)。迷ったらコピー です — 元には決して触れません。

条件範囲:WHERE 句はセルの中に置かれる

ほかの言語から来ると異質に感じる部分がこれです。AdvancedFilter は条件を文字列や式として 取りません。その条件は 条件範囲 の中に置かれます — ワークシートのセルの小さなブロックです。 先頭行は 元と一致する列見出し を保持し、その下の行が条件を保持します。

   H            I
1  Region       Amount
2  West         >1000

この条件範囲は「Region が West かつ Amount > 1000」を意味します。同じ行 の条件は AND別々の行 に積んだ条件は OR です。だから次の 2 行は —

   H
1  Region
2  West
3  East

— 「Region が West または East」を意味します。このブロックは、マクロが所有するセル(作業用の 一角、あるいは隠しシート)に作り、そこへ CriteriaRange を向ければよいのです。

ws.Range("A1").CurrentRegion.AdvancedFilter _
        Action:=xlFilterCopy, _
        CriteriaRange:=ws.Range("H1:I2"), _
        CopyToRange:=ws.Range("K1")

CriteriaRange をまるごと省けば、条件は何も適用されません — これを Unique:=True と組み合わせる のが、まさに素の重複なしリストを得る方法です。

Unique:=True — 何も削除せずに重複のないリストを作る

Unique:=True を設定すると、AdvancedFilter は重複のない行(単一列なら値)を 1 つずつ 返し ます — 重複の削除 と同じ結果ですが、一意な値を外へ コピーし元をそのまま残す 点が 違います。このたった 1 つの性質こそ、AdvancedFilter が安全な重複除去の方法である理由です。

' 重複のない顧客名を K 列へ、元のリストはそのまま。
ws.Range("C1:C5000").AdvancedFilter _
        Action:=xlFilterCopy, _
        CopyToRange:=ws.Range("K1"), _
        Unique:=True

RemoveDuplicates が取り消しなしにその場で削除するのに対し、こちらは真新しい重複除去済みの リストを手渡し、元を危険にさらすことは決してありません。「データを壊さずに VBA で一意な値を 得るには?」と聞かれたら、これが答えです。

空の出力を返す、見出し不一致の罠

AdvancedFilter が「何も返さない」第 1 位の理由は、見出しの不一致です。CriteriaRange の 見出しと CopyToRange の見出しは、どちらも元の見出しと 正確に 一致しなければなりません — 同じつづり、同じ空白、大文字小文字を無視して同じテキスト。「Reigon」(打ち間違い)という条件 見出しや、先頭セルが空白または誤ってラベル付けされた CopyToRange は、エラーを出さずに 空 または間違った出力を生みます。

これを防ぐ習慣が 2 つあります。

  • 条件とコピー先の見出しは、打ち直すのではなく 本物の見出しセルをコピーして 作ること。
  • 別のシートにフィルターするなら、古いルールを思い出してください。古典的な AdvancedFilterCopyToRangeアクティブシート上 にあることを求めます。頑健なパターンは、結果が着地する シートからフィルターを実行するか、元のシート上の作業範囲にフィルターしてから結果をあとで移す ことです。

出力が空で返ってきたら、ほかの何よりも先に見出しを確認しましょう。

AdvancedFilter と AutoFilter と RemoveDuplicates

混同するほど重なり、区別が効くほど違う 3 つです。

  • AutoFilterビュー。行をその場で隠してユーザーに部分集合を 見せます。何もコピーも削除もされません。フィルターした範囲を 見せる ために手を伸ばします。
  • AdvancedFilter(コピーモード)クエリ。一致した、あるいは一意な行を、非破壊的に 新しい場所へ抽出します。結果を データとして 必要とするときに手を伸ばします。
  • RemoveDuplicates削除。データをその場で縮め、各値の 最初を残し、取り消しなし。元そのものを本当に小さくしたく、バックアップがあるときにだけ手を 伸ばします。

覚えておく価値のある一言はこうです。AutoFilter は見せ、RemoveDuplicates は壊し、 AdvancedFilter は元に触れずに 抽出する — 重複のないリストや条件に一致したコピーを。 フィルターしたリストや一意なリストを作るためにループを書いている自分に気づいたら、それは AdvancedFilter です。

ExcelMaster の活用

AdvancedFilter が強力なのは、まさに扱いが細かいからです — その場かコピーかの分岐、一字一句 一致する見出しとともにセルの中に置かねばならない条件範囲、コピー先の宛先とそのアクティブ シートのルール、Unique フラグ。見出しをどれか 1 つでも間違えれば、静かに、何も返しません。

ExcelMaster なら、 クエリを説明するだけで済みます。「West 地域の 1000 超の注文をすべて新しいシートに引き出して」 「商品コードの重複のないリストをちょうだい」と言えば、元からコピーした見出しとともに条件範囲を 並べ、有効な CopyToRange でコピーモードを選び、重複のない値が欲しいときは Unique を設定し、 元データはそのまま残します。ブックもコードもあなたの手元に残り、打ち間違えた条件見出しがなぜ 空の結果を返したのかと悩む 30 分だけを飛ばせます。

よくある質問

VBA で Advanced Filter を使うには?

元の範囲に対して AdvancedFilter を呼びます。結果をどこか別の場所にコピーするには (CopyToRange とともに)Action:=xlFilterCopy を、一致しない行を隠すには xlFilterInPlace を 選びます。条件には CriteriaRange を与えるか、重複のないリストを抽出するには条件なしで Unique:=True を設定します。コピーモードでは元データは変更されません。

VBA の Advanced Filter で一意な値を抽出するには?

コピーモードで、条件なしに Unique:=True を使います。rng.AdvancedFilter Action:=xlFilterCopy, CopyToRange:=ws.Range("E1"), Unique:=True のように。重複のない各値を 1 つずつ宛先に書き出し、 元をそのまま残します — その場で削除する RemoveDuplicates とは違います。CopyToRange の見出しは 元の見出しと一致しなければなりません。

VBA の Advanced Filter が何も返さないのはなぜ?

ほぼ必ず見出しの不一致です。CriteriaRangeCopyToRange の先頭行の見出しは、元の見出しと 正確に一致しなければなりません(打ち間違いや空白の見出しは、エラーなしに空の出力を返します)。 見出しは打ち直さずに本物のセルをコピーし、コピーモードのフィルターには有効な CopyToRange が あることを確かめましょう。

VBA の AutoFilter と Advanced Filter の違いは?

AutoFilterビュー を生みます — 一致しない行をその場で隠し、何もコピーしません。 AdvancedFilterデータ を生みます — コピーモードでは、元を変えずに一致した、あるいは一意な 行を新しい場所へ抽出し、AutoFilter にはできない複雑な AND/OR 条件と一意抽出に対応します。

VBA の Advanced Filter で条件はどう働く?

条件はコードではなく、セルの範囲の中に置かれます。先頭行は元と一致する見出しを保持し、同じ行の 条件は AND で、別々の行の条件は OR で結合されます。そのブロックへ CriteriaRange を向けます。 条件を何も適用しないなら省きます(Unique:=True と組み合わせると便利です)。

検証環境

動作確認: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-10。

関連ガイド: VBA AutoFilter · VBA Remove Duplicates · VBA Sort · VBA Find · VBA Range