【ツール提供】Excelユーザなら全員使える?! Excelフィルタリングツール

# 1. はじめに
ＡＲアドバンストテクノロジ株式会社（ＡＲＩ）の鈴木タクヤです。

以下リンク先の記事を書いてから半年以上過ぎ、私もExcelマクロによる簡単な自動化ツールをVBA[^1]で作成し、業務で使用できるようになりました。
[^1]: VBA：___V___ isual ___B___ asic for ___A___ pplication の略。Microsoft Office のアプリケーションの機能を拡張するためのプログラミング言語。

https://qiita.com/TakuyaSuzuki/items/7081cd8ee99c7c1b6e9c

そこで今回は、汎用性が高くExcelを使う人なら全員使えるのではないかと思われる（私見）、「オートフィルター」に関するツールを作成したので、こちらで共有します。是非使ってみてください。

:::note
ツール（のコード）は無償配布です。無断で使用・拡散いただいて構いませんが、記事への「いいね」をいただけますと幸いです。
:::

以下、本記事では

　[2. ツールの概要](#2-ツールの概要)
　[3. ツールの導入方法](#3-ツールの導入方法)
　[4. VBAのソースコード](#4-vbaのソースコード)
　[5. 解説記事のリンク](#5-解説記事のリンク)

について記載します。

（このツールの詳細な説明に関連して、「[Excelフィルタリングツール解説シリーズ](#5-解説記事のリンク)」として、不定期で連載する予定です。）

# 2. ツールの概要
以下で紹介するツールは、Excelの表のフィルタリング条件を設定した後、1ボタンでその設定を適用したり、フィルターを解除して全行を表示したりするものになります。

:::note
Excelを使用した業務でありがちな以下の作業が効率化されます。
・定期的に更新される表に毎回決まった条件でフィルターをかける
・表にフィルターをかけて更新し、フィルター解除後に上書き保存
　など
:::

:::note warn
フィルター対象のシートに非表示の列がある場合、正常に動作しない場合があります。列の再表示後にツールを実行し直してください。
:::

:::note
以下、画面キャプチャは「Microsoft® Excel® for Microsoft 365 MSO (バージョン 2310 ビルド 16.0.16924.20054) 64 ビット」のものです。
:::

__①以下のような表のフィルタリングの場合、__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/88f7ad13-bd27-e6b4-df05-d97f39185aaa.png)


__②ツールのA1～A5セルに対象のExcelファイルと表見出しの端のセルの情報を入力し、__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/3af61b9b-66ca-733d-b07c-e0710aa9c470.png)


__③「表見出しのコピー」ボタンを押下すると、コピーした表見出しをA7セルから貼り付けます。__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/e8d2b28a-60fd-babd-e854-15f86c140f59.png)

__④コピーされた見出しの下に抽出条件を入力し「フィルタリング」ボタンを押下すると、__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/73ea7a36-7278-f325-3b11-e18ad4ee9fab.png)

__⑤フィルタリングされます！__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/0a1e3ede-8b61-ff22-7654-4bcc289cabe6.png)

:::note
※ワイルドカードも使用可能で、__「*」を入力すると空白セル以外、「=」を入力すると空白セルのみ抽出可能です！！__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/cf595281-31d5-d527-85b8-b24d1713edae.png)
:::

__⑥そして「フィルタのクリア」ボタン押下で表が全行表示されます！__
（ファイルの上書き保存の際に便利）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/c7dcb596-5dc0-2734-0ed8-720c5e061a66.png)

:::note
__※見出しが複数行の場合にも対応しています。__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/99e08777-bc92-7e33-b0e5-fb8c4581446b.png)
:::


# 3. ツールの導入方法
### 3-1 VBAコードのコピー&ペースト
①ツール用のExcelファイル（以下フィルタリングツール）を新規で作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/fc068a98-864a-d8f1-055d-ce1369ecd1ed.png)

②「開発」タブの「Visual Basic」（もしくは Alt + F11）を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/673151ff-dd86-cf14-a3b2-9af93e12b907.png)
__※「開発」タブがリボンに存在しない場合は「ファイル」タブ-（「その他...」-）「オプション」で表示する「Excelのオプション」画面で、「リボンのユーザー設定」からリボンに「開発」を追加できます。__
<img width="150" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/9d2aa20e-95d8-65bd-d40f-ec79511b09c0.png">
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/3edd6c47-f1a0-4332-5295-438b7413113c.png)

③ Visual Basicの画面左側の階層にて①で作成したファイル配下が選択されている状態で、「挿入」タブの「標準モジュール」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/2da79242-f6f9-950f-9a0a-4d9408ef81b6.png)

④作成された「Module1」に、 [4. VBAのソースコード](#4-vbaのソースコード) に記載のソースコードをコピー＆ペーストします。

:::note
本記事をPCから表示した場合は、マウスポインタをコードブロックの上に移動すると右上に表示されるボタン押下で簡単に全行コピーできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/b8b63378-a2cb-1a3e-a34d-450edb498208.png)
:::

（「Module1」 に Ctrl + V 等でペースト）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/b9776092-069a-00e5-de0f-06184f53427d.png)

⑤フィルタリングツールを「マクロ有効ブック(*.xlsm)」として（お好きなファイル名で、お好きな場所に）保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/5dee30ff-0e31-5a39-a63e-50bbbe048a09.png)

### 3-2 フィルタ対象の情報を入力
①フィルタリングツールに以下の情報を入力します。
  - A1セル：フィルタリングしたいブックの保存されているフォルダの絶対パス（対象ファイルの場所）
  - A2セル：フィルタリングしたいブックのファイル名
  - A3セル：対象シート名
  - A4セル：フィルタリングしたい表の見出し左上端のセル番地
  - A5セル：フィルタリングしたい表の見出し右下端のセル番地
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/a467383e-71b1-d950-ea6f-f810a564c26e.png)
__※A1セルに入力する内容は対象ブックをフォルダ上で右クリック-「プロパティ」の「全般」タブ-「場所」からコピー&ペーストできます。__<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/d2bb1c1e-a3f4-42bd-33fb-a0520788c72f.png">

### 3-3 マクロ実行用のボタンの配置
①「開発」タブ-「挿入」-「ボタン（フォームコントロール）」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/621357b4-695a-447f-d42f-642c9d2fe9d4.png)

②マウスポインタが「＋」になったことを確認し、ボタンを配置したい箇所にドラッグしてボタンを作成します。

:::note alert
フィルタリングツールの7行目以降はマクロの処理で削除されることがあるため、ボタンを配置しないでください！！
:::

③「マクロの登録」画面で「__copyHeader__」をWクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/c3b5edb6-34cf-9944-e3cf-68c98afe8acc.png)

④「ボタン1」が作成されるので、ボタンを右クリック-「テキストの編集」からボタンの用途「__表見出しのコピー__」を入力し、適宜ボタンの幅を調整します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/d2a85b57-06b5-9c89-ea64-288facd4188b.png)

⑤上記の①～④と同様の手順で「フィルタのクリア」「フィルタリング」「処理中ポインタ解除」のボタンも作成します。対応するマクロ名（上記③マクロの登録画面でWクリックするもの）は以下の通りです。

:::note
- 「フィルタのクリア」
　⇒「__clearFilter__」
- 「フィルタリング」
　⇒「__filter__」
- 「処理中ポインタ解除」
　⇒「__endMacro__」
:::
※「exeCommonProc」は他のマクロ処理から間接的に呼ばれるため、対応するボタンは不要です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/a024ce4f-5d2b-75dd-9e9c-de088a96666b.png)

__以上で導入完了です！おつかれさまでした！！__
「表見出しのコピー」を押下してフィルタリングしたい表の見出しが表示されること、抽出条件入力後に「フィルタリング」押下で対象の表がフィルタリングされること等を確認してみてください。

:::note warn
※ツールの使用前に、念のため対象ファイルのバックアップの取得をおすすめします。
:::

:::note warn
簡単なエラーハンドリングはしていますが、マクロの実行時エラーとなった場合には、ポップアップの「終了」ボタンを押下してください。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/c7e7da27-8a79-89c0-62c5-783c7c9251a9.png)
この場合、マウスポインタが処理中の状態のままとなるので、上記⑤で作成した「処理中ポインタ解除」ボタンを押下してください。
:::

__次回からは本ツールのコード解説編です。具体的な処理の流れや、実行時エラーでマウスポインタが復旧しない理由なども記載予定ですので、そちらも「いいね」をいただけますと私が大いに喜びます！！__

[Excelフィルタリングツール解説シリーズ](#5-解説記事のリンク)

# 4. VBAのソースコード

```vb:Excelフィルタリングツール
'このツールの設定値を代入する変数の定義
Dim modeNo As Integer                   'マクロの起動モード設定用（0:表見出しのコピー, 1:フィルタリング, 2:フィルタのクリア）
Dim settingSheetName As String          'フィルタ条件等を記載する本ツールの設定用シート名
Dim targetBookPath As String            'フィルタ対象のExcelブック格納先（フォルダのパス）
Dim targetBookName As String            'フィルタ対象のExcelブック名
Dim fullPath As String                  'フィルタ対象のExcelブックの絶対パス
Dim targetSheetName As String           'フィルタ対象のExcelシート名
Dim startingCell As String              '表見出し左上端セル
Dim endCell As String                   '表見出し右下端セル

Dim settingBook As Workbook             'フィルタリングツール（このブック）
Dim targetBook As Workbook              'フィルタ対象ブック


'■共通処理（複数のマクロから呼ばれる）
Sub exeCommonProc()
    
    '処理高速化のおまじない
    With Application
        .ScreenUpdating = False
        .Calculation = xlCalculationManual
        .EnableEvents = False
        .Cursor = xlWait
    End With
    
    'メイン処理開始
    settingSheetName = ActiveSheet.Name     'シート名を取得
    
    '変数に設定値を代入
    targetBookPath = Sheets(settingSheetName).Range("A1").Value
    targetBookName = Sheets(settingSheetName).Range("A2").Value
    fullPath = targetBookPath & "\" & targetBookName
    targetSheetName = ThisWorkbook.Sheets(settingSheetName).Range("A3").Value
    startingCell = Sheets(settingSheetName).Range("A4").Value
    endCell = Sheets(settingSheetName).Range("A5").Value
    
    Set settingBook = Workbooks(Application.ThisWorkbook.Name)
    
    '既に対象ブックを開いているか確認する
    If isOpened(targetBookName) = True Then
        Set targetBook = Workbooks(targetBookName)
    Else
        '対象ブックの存在確認＆設定
        Set targetBook = setFile(fullPath)
    End If
    
    '対象シートの存在確認/活性化
    Call activateSheet(targetSheetName, targetBook)
    
    '表見出し左上端セル番地のフォーマットチェック
    startingCell = checkFormat(startingCell)
    
    '表見出し右下端セル番地のフォーマットチェック
    endCell = checkFormat(endCell)

End Sub

'■表見出しのコピー処理
Sub copyHeader()

    '起動モードを設定
    modeNo = 0

    '共通設定処理の呼び出し
    Call exeCommonProc
    
    '以下、ツールの設定用シート操作
    With settingBook.Sheets(settingSheetName)
        '設定用シートを活性化
        .Activate
        'ざっくり7行目から10行削除
        .Rows("7:16").Select
        Selection.Delete Shift:=xlUp
    
        '表見出しをツールのA7セルから貼り付ける
        targetBook.Sheets(targetSheetName).Range(startingCell, endCell).Copy Destination:=.Range("A7")
        
        'A1セルに戻る
        .Range("A1").Select
    
    End With
    
    'マクロ終了処理の呼び出し
    Call endMacro

End Sub

'■フィルタリング処理
Sub filter()

    '起動モードを設定
    modeNo = 1

    'フィルタのクリア処理の呼び出し
    Call clearFilter
    
    'フィルタリング処理
    With settingBook.Sheets(settingSheetName)
    
        'ループ用変数定義
        Dim searchValRowNo As Integer   '検索値記載開始行番号
            searchValRowNo = Range(endCell).Row - Range(startingCell).Row + 8   '初期化（7行目から表見出しをコピーした場合）
        
        Dim i As Integer, j As Integer  'ループカウンタ
        Dim searchVal() As String       '検索値格納用配列
        Dim elementsCount As Integer    '検索値格納用配列の要素数
        
        '列移動に関するループ開始（1列目から検索値を確認していく）
        For j = 1 To (Range(endCell).Column - Range(startingCell).Column + 1)
            '検索値が空文字でなければ、検索値を配列に格納
            If .Cells(searchValRowNo, j).Value <> "" Then
                elementsCount = .Cells(Rows.Count, j).End(xlUp).Row - searchValRowNo    '配列の要素（指定された検索値）の数を計算
                ReDim searchVal(elementsCount)                                          '配列の要素数を確定　※配列のインデックスは0から
                
                For i = 0 To (.Cells(Rows.Count, j).End(xlUp).Row - searchValRowNo)     '検索値を上から順に配列に格納するためのループ処理
                    searchVal(i) = .Cells(searchValRowNo + i, j).Value                  '※配列のインデックスは0から
                Next i
                
                'Withブロックの入れ子に注意！！
                With targetBook.Sheets(targetSheetName)
                
                '対象シートにフィルタを適用
                    .Range(Cells(Range(endCell).Row, Range(startingCell).Column), Cells(Cells(Rows.Count, .Range(startingCell).Column).End(xlUp).Row, Range(endCell).Column)) _
                    .AutoFilter Field:=j, Criteria1:=Array(searchVal), Operator:=xlFilterValues
                    
                End With
                
            End If
        
        Next j
        
    End With

    'マクロ終了処理の呼び出し
    Call endMacro

End Sub

'■適用済みフィルタのクリア処理
Sub clearFilter()

    '起動モードを設定；modeNo=1:フィルタリング でないときは 2:フィルタのクリア に設定する
    If modeNo <> 1 Then
        modeNo = 2
    End If
    
    '共通設定処理の呼び出し
    Call exeCommonProc
    
    With targetBook.Sheets(targetSheetName)
        'フィルタリング済みの場合は解除
        If .AutoFilterMode Then
            .Range("A1").AutoFilter
        End If
        
        'オートフィルタのドロップダウンを表示
        '.Range(Cells(Range(endCell).Row, Range(startingCell).Column), Cells(Cells(Rows.Count, .Range(startingCell).Column).End(xlUp).Row, Range(endCell).Column)).AutoFilter
        
    End With
    
    '起動モードが 2:フィルタのクリア の場合、マクロ終了処理の呼び出し
    If modeNo = 2 Then
        Call endMacro
    End If

End Sub


'■指定のブックを開いているか否かを判定する関数
Function isOpened(ByVal bookName As String) As Boolean
    isOpened = False
    Dim wb As Workbook
    isOpened = False
    
    For Each wb In Workbooks
        If wb.Name = bookName Then
            isOpened = True
            Exit For
        End If
    Next
    
    Set wb = Nothing
End Function

'■対象ファイル存在確認/設定関数（渡されたfullPathのファイルが存在すればそれを返し、存在しなければエラーメッセージを表示する。）
Function setFile(ByVal fullPath As String) As Workbook
    Dim fileChecker As Object
    Set fileChecker = CreateObject("Scripting.FileSystemObject")
    
    If fileChecker.FileExists(fullPath) Then
        Set setFile = Workbooks.Open(fullPath)
    Else
        MsgBox "ファイル「" & fullPath & "」が存在しません。"
        Call endMacro
    End If
    
    Set fileChecker = Nothing
End Function

'■対象シート存在確認/活性化処理（渡されたブック・シート名に該当するシートが存在すれば活性化し、存在しなければエラーメッセージを表示する。）
Sub activateSheet(ByVal sheetName As String, ByVal wb As Workbook)
    Dim ws As Worksheet
    Dim sheetExists As Boolean      '初期値はFalse
    
    For Each ws In wb.Worksheets
    If ws.Name = sheetName Then
        wb.Sheets(sheetName).Activate
        sheetExists = True
        Exit For
    End If
    Next
    
    If Not sheetExists Then
        MsgBox "シート「" & sheetName & "」が「" & wb.Name & "」に存在しません。"
        Call endMacro
    End If
    
    Set ws = Nothing
End Sub

'■セル番地のフォーマットチェック関数
Function checkFormat(ByVal cellReference As String) As String
    '全て半角大文字に置換
    cellReference = UCase(StrConv(cellReference, vbNarrow))
    '文字数を変数に代入
    Dim wordCount As Integer
    wordCount = Len(cellReference)
    
    '文字列が「英字部分・数字部分」の構成になっていることを確認
    If Not cellReference Like "[A-Z]*" Then             '先頭が英字であることを確認
        Call showFormatErrorMessage(1)
    End If
    
    If Not cellReference Like "*[0-9]" Then             '末尾が数字であることを確認
        Call showFormatErrorMessage(wordCount)
    End If
    
    Dim startingPositionOfRowNo As Integer              '数字の開始位置が先頭から何文字目かを格納する変数を定義
    Dim i As Integer, j As Integer                      'ループ処理用変数を定義
    '2文字目以降は1文字ずつ英字か数字か確認
    For i = 2 To wordCount
        If Mid(cellReference, i, 1) Like "[0-9]" Then
            startingPositionOfRowNo = i                 '数字部分（行番号）開始が先頭から何文字目かを保持
            Exit For
        ElseIf Not Mid(cellReference, i, 1) Like "[A-Z]" Then   '数字じゃなくて英字でもなければエラー
            Call showFormatErrorMessage(i)
        End If
    Next i
    
    '数字部分（行番号）の2文字目以降が（存在すれば）全て数字であることを確認
    j = startingPositionOfRowNo + 1
    Do While j <= wordCount
        If Not Mid(cellReference, j, 1) Like "[0-9]" Then       '数字以外だったらエラー
            Call showFormatErrorMessage(j)
        End If
        
        j = j + 1
    Loop
    
    '英字部分（列番号）が上限（XFD）以下であることを確認する
    Dim columnNo As String
    columnNo = Left(cellReference, startingPositionOfRowNo - 1)
    
    '英字部分が4桁以上の場合はエラー
    If startingPositionOfRowNo >= 5 Then
        Call showFormatErrorMessage(4)
    End If
    
    '英字部分が3桁の場合の整合性チェック
    If startingPositionOfRowNo = 4 Then
        If (Mid(cellReference, 1, 1) Like "[Y-Z]") _
            Or (Mid(cellReference, 1, 1) = "X" And Mid(cellReference, 2, 1) Like "[G-Z]") _
            Or (Mid(cellReference, 1, 1) = "X" And Mid(cellReference, 2, 1) = "F" And Mid(cellReference, 3, 1) Like "[E-Z]") _
            Then
            
            Call showFormatErrorMessage(3)
        End If
    End If
    
    '数字部分（行番号）が上限（1048576）以下であることを確認する
    Dim rowNo As Long
    rowNo = CLng(Right(cellReference, wordCount - startingPositionOfRowNo + 1))
    
    If rowNo > 1048576 Then
        Call showFormatErrorMessage(wordCount)
    End If
    
    checkFormat = cellReference                         '確認済みの文字列を戻り値に設定
End Function

'■フォーマットエラーメッセージ表示処理
Sub showFormatErrorMessage(ByVal NoFromTheBeginning As Integer)
    MsgBox "表見出しの両端を表すセル番地は" & vbCrLf & "列：英字、行：数字（例：A1 など）で指定してください" _
           & vbCrLf & "　<エラー箇所>　" & NoFromTheBeginning & "文字目"
    Call endMacro
End Sub

'■マクロ終了処理（処理終了直前にしたいことを実行・エラー落ち時の処理中ポインタ解除）
Sub endMacro()
    
    '処理高速化のおまじない解除
    With Application
        .Cursor = xlDefault
        .EnableEvents = True
        .Calculation = xlCalculationAutomatic
        .ScreenUpdating = True
    End With
    
    End
    
End Sub
```
# 5. 解説記事のリンク
第1回

https://qiita.com/TakuyaSuzuki/items/158ec6815509fd27de67

第2回

https://qiita.com/TakuyaSuzuki/items/cbb8f2e32cc0294f53fe

第3回

https://qiita.com/TakuyaSuzuki/items/1fc0a6c9411e585c8f64

第4回

https://qiita.com/TakuyaSuzuki/items/4402237239e338368257

第5回

https://qiita.com/TakuyaSuzuki/items/2486e705198b5a70e235

第6回

https://qiita.com/TakuyaSuzuki/items/2bd2c757be640f252b89

第7回

https://qiita.com/TakuyaSuzuki/items/a38b2356d823a67f87ea

第8回

https://qiita.com/TakuyaSuzuki/items/4bad627f7a8a71eb1b30

・
・
・
第9回以降
__...Comming Soon!!?__