大量のデータを絞り込むには、オートフィルタが便利です。ここでは、VBAからオートフィルタを使い倒すテクニックをご紹介します。なお、ボリュームがありますので、以下の項目にページを分けて解説します。なお、ここで解説するオートフィルタは、通常のワークシートに設定されているとします。テーブルでオートフィルタを操作するときは、また別の考え方が必要です。VBAでテーブルを扱う方法に関しては「VBAでテーブルの操作」をご覧ください。
下図のような表を例にします。いかにも、文字列で絞り込みそうな表です。
1列目を「"田中"と等しい」で絞り込むには、次のようにします。
Sub Macro1() Range("A1").AutoFilter 1, "田中" End Sub
2番目の引数Criteria1には、絞り込みの条件を文字列形式で指定します。本項のテーマは「文字列で絞り込む」ですから、必然的に条件も文字列形式になりますが、条件に数値や日付を指定するときは、この「文字列形式で指定する」が重要なポイントになってきますので、しっかり認識してください。
条件に指定した「"田中"」というのは、本当は「"=田中"」という意味です。オートフィルタでは、条件に指定する文字列の先頭に「=」「>」「<」などの記号を含めなければなりません。しかし、どの記号もついていないときは「=」と見なされます。「"田中"」が本当は「"=田中"」だということを理解していると「"田中"ではない」という条件をどう書けばいいかも分かりますね。
Sub Macro2() Range("A1").AutoFilter 1, "<>田中" End Sub
実務でよくある「空欄のセル」で絞り込むには、条件に「""」を指定します。空欄ですから""です。もちろん、このときも本来は先頭に「=」「>」「<」などの記号を含めなければなりません。何もつけないと「=」という意味なのですから「空欄のセル」で絞り込むときは「""」だけでなく「"="」でもOKです。
Sub Macro3() Range("A1").AutoFilter 2, "=" ''「""」でもOK End Sub
ここまで理解できれば「空欄ではないセル」も分かりますね。
Sub Macro4() Range("A1").AutoFilter 2, "<>" End Sub
セルに入力されている値が文字列だったときは、条件にワイルドカードを使えます。セルの値が数値や日付だったとき、条件にワイルドカードを指定してもエラーにはなりませんが、もちろん正しく動作しません。
Sub Macro5() Range("A1").AutoFilter 3, "東京*" ''"東京"で始まる End Sub
Sub Macro6() Range("A1").AutoFilter 3, "*北区" ''"北区"で終わる End Sub
Sub Macro7() Range("A1").AutoFilter 3, "*中*" ''"中"を含む End Sub
これ、セミナーで質問されたので書いておきます。もし、セルに入力されている値が「*」や「?」などワイルドカードで使われる文字列や、「=」「>」「<」などオートフィルタの条件として使われる記号だったケースです。順番にご紹介します。
【ワイルドカード】
「*」と「?」のワイルドカードを文字列として条件に指定するときは、「*」と「?」の前に半角のチルダ(~)をつけます。これは、ワークシート内で「*」と「?」を検索するときと同じです。
Sub Macro8() Range("A1").AutoFilter 1, "~*" End Sub
Sub Macro9() Range("A1").AutoFilter 1, "~?" End Sub
【記号】
分かりにくいのが「=」「>」「<」などの記号です。これらの記号を文字列として条件に指定するときは、記号の前に、さらに「=」をつけます。たとえば「=」という文字列を条件に指定するときは「==」とします。
Sub Macro10() Range("A1").AutoFilter 1, "==" End Sub
「>」と「<」も同様です。先頭に「=」をつけます。
Sub Macro11() Range("A1").AutoFilter 1, "=>" End Sub
Sub Macro12() Range("A1").AutoFilter 1, "=<" End Sub
条件は、引数Criteria1と引数Criteria2に2つまで指定できます。もし、2つの引数を指定するときは、引数OperatorにxlAndやxlOrなどを指定します。
よく見る間違いですが、AutoFilterrメソッドには、条件を2つしか指定できません。
Range("A1").AutoFilter 1, "田中", xlOr, "広瀬", xlOr, "桜井" ''エラー
上記のように書くとエラーです。なぜ2つしか指定できないのかというと、Excel 2003までのオートフィルタは、ひとつの列に2つしか条件を指定できなかったからです。Excel 2007になってオートフィルタの仕様が拡張され、ひとつの列に3つ以上の条件を指定できるようになりました。しかし、VBAのAutoFilterメソッドは、Excel 2003以前に作られたメソッドです。ですから、当時は2つで十分だったんです。ひとつの列に3つ以上の条件を指定する書き方は、次項をご覧ください。
Sub Macro13() Range("A1").AutoFilter 1, "田中", xlOr, "広瀬" End Sub
ここで指定した"田中"と"広瀬"は、それぞれ"=田中"と"=広瀬"という意味です。したがって、次のような指定も可能です。
Sub Macro14() Range("A1").AutoFilter 1, "<>田中", xlAnd, "<>広瀬" End Sub
ひとつの列に、3つ以上の条件を指定する操作をマクロ記録すると、おおむね次のようなコードが記録されます。
Sub Macro15() Range("A1").AutoFilter 1, Array("田中", "広瀬", "桜井"), xlFilterValues End Sub
条件を指定する引数Criteria1には配列を指定します。引数Operatorには、定数xlFilterValuesを指定します。この定数は、ある意味"お約束"です。このように、Array関数を使って配列を指定してもいいですが、Array関数は、項目数を可変にすることができません。今回は3項目で、次は4項目で…のようなケースで、Array関数は使い勝手が悪いです。ひとつの列に3つ以上の条件を指定するときは、引数Criteria1に配列を指定すればいいのですから、この配列は自分で作った方がいいでしょう。
Sub Macro16() Dim A(2) As String A(0) = "田中" A(1) = "広瀬" A(2) = "桜井" Range("A1").AutoFilter 1, A, xlFilterValues End Sub
もし条件に指定する項目数が可変になる場合は、動的配列を使います。動的配列に関しては「部屋数を変えられる動的配列」をご覧ください。ここでは、条件が別のセルに入力されているケースで考えてみましょう。実務では"あるある"ですね。
上図のように、条件に指定したい項目がE列に入力されていたとします。
Sub Macro17() Dim i As Long ReDim A(Cells(Rows.Count, 5).End(xlUp).Row - 1) For i = 0 To UBound(A) A(i) = Cells(i + 2, 5) Next i Range("A1").AutoFilter 1, A, xlFilterValues End Sub
注意が必要なのは、このように、ひとつの列に3つ以上の条件を指定する場合は、必ず「と等しい」という指定しかできないことです。先の考え方で
Sub Macro16() ''できない Dim A(2) As String A(0) = "<>田中" A(1) = "<>広瀬" A(2) = "<>桜井" Range("A1").AutoFilter 1, A, xlFilterValues End Sub
という指定はできませんし、次のようにワイルドカードを使うこともできません。
Sub Macro16() ''できない Dim A(2) As String A(0) = "田*" A(1) = "広?" A(2) = "*桜*" Range("A1").AutoFilter 1, A, xlFilterValues End Sub
これは、手動操作を考えてみれば分かります。
ここで「"田中"ではない」や「"広"で始まる」を指定することはできませんよね。手動でできないことは、VBAでもできません。それは、オートフィルタの仕様だからです。どうしても、そういう条件を指定したいのでしたら「作業列で絞り込む」を参照してください。
あと、これはVBAに限った話ではなく、Excelの仕様なんですけど。文字列を条件にして絞り込むとき、セルに入力された文字列の前後に、半角スペースがあっても無視されます。次の表で確認してみましょう。
セルA2には、普通に"田中"と入力しています。文字数を調べるLEN関数も2となっていますね。セルA3には" 田中"と先頭に半角スペースを入れています。セルA4は分かりにくいですが"田中 "と後ろに半角スペースがあります。この表に対して「1列目が"田中"と等しい」という条件で絞り込んでみましょう。
Sub Macro17() Range("A1").AutoFilter 1, "田中" End Sub
結果は次のとおりです。
これは、手動でオートフィルタを操作しているときも同じです。A列の▼ボタンをクリックすると次のようになります。
リストには"田中"しか出てきません。それに、選択した"田中"をよく見ると、前後にスペースも存在していません。オートフィルタでは、文字列の前後にある半角スペースは無視されるということです。ですから、ちなみにですけど、次のようなコードでも"田中"で絞り込まれます。
Sub Macro17() Range("A1").AutoFilter 1, " 田中 " End Sub
もちろん、無視されるのは半角のスペースだけです。次のように全角のスペースが存在した場合は、別の文字列として区別されます。
リストアップされている3つの候補が分かりにくいですから、拡大してみましょう。
このように「半角スペースが無視される」というのは、Excelの中でオートフィルタだけです。なので、半角スペースの存在に気がつかないと、次のように、他の関数や機能と結果が合わない…と慌てることになります。
上図の表は、セルA4だけ"田中 "と後ろにスペースが入っています。まずはこの表を「1列目が"田中"と等しい」で絞り込みます。これは、VBAでも手動操作でも同じことです。
オートフィルタで絞り込んだ結果をSUBTOTAL関数で計算してみます。
見えているとおりの結果になりますね。では、同じ計算をCOUNTIF関数とSUMIF関数でやってみましょう。
結果が異なります。COUNTIF関数とSUMIF関数は、半角スペースが含まれている"田中 "を、"田中"とは別の文字列だと認識します。これは、ピボットテーブルも同じです。
元データに半角のスペースが含まれているかどうかは、目に見えないだけに注意が必要です。