はじめに
みなさん、こんにちは!今回は、多くの方から質問をいただく「VBAでのCountIfs」について、できるだけ分かりやすく解説していきたいと思います。
私が経験した「CountIfs関数のあるある」から話を始めましょう。実は先日、ある営業部の方から「CountIfsを使ったマクロを作ったんですが、動作が重くて…」という相談を受けました。セルに直接CountIfsを入れていたため、別のマクロ実行のたびに全行が再計算されて、とんでもなく遅くなっていたんです。
用語解説:CountIfs
Excelの関数の一つで、複数の条件に一致するセルの個数を数える関数です。例えば「東京の営業部の売上」のように、複数の条件でデータを集計する際に便利です。
VBAでCOUNTIFSを使う基本
Application.WorksheetFunctionの基礎知識
まずは、実際のエクセルデータを見てみましょう。以下のような売上データがあるとします:
![売上データ例](https://rebizru.com/wp-content/uploads/2025/02/0e21cf0853dc210daed7663a6dcaec58.png)
このデータに対して、VBAでCOUNTIFSを使う基本的な書き方は以下のようになります:
'基本的な書き方
Dim result As Long
result = Application.WorksheetFunction.CountIfs(Range("B:B"), "東京")
'→ B列(地域)から「東京」の件数をカウント
COUNTIFSの基本的な書き方
実際のデータを使って、段階的に見ていきましょう。
1. 単純な条件での使用
例えば、「東京の売上件数を知りたい」場合:
Sub 東京カウント()
'B列の地域が東京のデータをカウント
Dim result As Long
result = Application.WorksheetFunction.CountIfs( _
Range("B:B"), "東京" _
)
Debug.Print result '確認用に結果を出力
End Sub
このコードを実行すると
![イミディエイトウィンドウに4が表示されている](https://rebizru.com/wp-content/uploads/2025/02/c7e7572a89c2bb8af7564244fa967cbf-3.png)
このように表示されます。
B列の「地域」に東京が4個あるため「4」という数字が表示されました。
![地域が東京のセルは4個あった](https://rebizru.com/wp-content/uploads/2025/02/f4512d1a6452b5ffeab55e8763a904d9.png)
Tips:イミディエイトウィンドウ
Debug.Print を使うと、イミディエイトウィンドウ(VBEの下部にある窓)に結果を表示できます。結果が正しいか確認するときに便利ですよ。
詳しくはイミディエイトウィンドウの表示方法 Excel(エクセル)マクロ(VBA)もチェックしてみてください。
2. 数値範囲での使用
「売上が10,000円以上の件数を知りたい」場合:
Sub 売上が10000円以上の件数()
'売上が10,000円以上のデータをカウント
Dim result As Long
result = Application.WorksheetFunction.CountIfs( _
Range("E:E"), ">=10000" _
)
Debug.Print result
End Sub
このコードを実行すると
![イミディエイトウィンドウに5が表示されている](https://rebizru.com/wp-content/uploads/2025/02/859de372d977c0ed57cff05d7ff220d1.png)
と表示されました。
E列の「売上金額」に1万円以上のセルが5個あるため「5」という数字が表示されました。
![売上金額が1万円以上のセルは5個あった](https://rebizru.com/wp-content/uploads/2025/02/fdac99c145e8918c89975113d1f091bc.png)
3. 複数条件の組み合わせ
「東京で、かつ売上が10,000円以上の件数を知りたい」場合:
Sub 東京で売上10000円以上()
'東京で売上10000円以上のデータをカウント
Dim result As Long
result = Application.WorksheetFunction.CountIfs( _
Range("B:B"), "東京", _
Range("E:E"), ">=10000" _
)
Debug.Print result
End Sub
このコードを実行すると
![イミディエイトウィンドウに2が表示されている](https://rebizru.com/wp-content/uploads/2025/02/7ae1a528cbd866060aa7434f73318f34.png)
と表示されました。
B列の「地域」が東京でE列の「売上金額」が1万円以上の行が2行あるため「2」という数字が表示されました。
![地域が東京で1万円以上の行は2行あった](https://rebizru.com/wp-content/uploads/2025/02/031bce18a8df24d715c4d4cf26781441.png)
このように、実際のデータと共に見ていくと、COUNTIFSの使い方がより具体的にイメージできますよね。
実践:具体的な使用例で学ぶ
売上データでの活用例
私が実際に営業部で対応した事例をご紹介します。毎日の売上集計で「地域別」「商品カテゴリ別」のクロス集計が必要だったんです。
サンプルデータ
![文房具の売上サンプルデータ](https://rebizru.com/wp-content/uploads/2025/02/0e21cf0853dc210daed7663a6dcaec58-1.png)
実装例1:地域×カテゴリのクロス集計
このように東京で文具が売れた回数を表示させたいセルがあったとします。
![東京で文具が売れた回数を表示させたいセル](https://rebizru.com/wp-content/uploads/2025/02/1e576041792dc458f56e3d86acb8199a.png)
Sub クロス集計()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("売上データ")
'東京の文具売上件数
Dim tokyoStationeryCount As Long
tokyoStationeryCount = Application.WorksheetFunction.CountIfs( _
ws.Range("B:B"), "東京", _
ws.Range("C:C"), "文具" _
)
ws.Range("I3").Value = tokyoStationeryCount
End Sub
このコードを実行すると
![東京で文具が売れた回数「2」が表示された](https://rebizru.com/wp-content/uploads/2025/02/4c7aebce81d16a10b5592d4718f18a3d.png)
このようにI3セルに、東京で販売された文具の件数「2」が表示されました。
![東京の文具は2行あった](https://rebizru.com/wp-content/uploads/2025/02/03b37f2fa37effda1013edaa113abc57.png)
サンプルデータの場合、2件(ノートA4と消しゴム)がカウントされました。
ちょっとしたコツ: ThisWorkbookは「このブック」という意味です。別のブックのデータを参照したい場合は、Workbooks(“ブック名”)を使います。
よくある失敗例と解決策
ここで、私が以前失敗した例をお話ししましょう。最初は以下のようなコードを書いていました:
For Each cell In Range("B:B")
If cell.Value = "東京" Then
If cell.Offset(0, 1).Value = "文具" Then
Count = Count + 1
End If
End If
Next cell
このコードでも同じ結果(2件)が得られますが、100万行あるシートだと全行をチェックしてしまうため、実行に数分かかってしまいました…。私も最初はこのコードで苦い経験をしました(汗)
このコードの問題点は2つあります:
- 全行をループするので、データが多いと極端に遅くなる
- 空白行もチェックしてしまう
そこで、以下のように改良しました:
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("売上データ")
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
Dim result As Long
result = Application.WorksheetFunction.CountIfs( _
ws.Range("B2:B" & lastRow), "東京", _
ws.Range("C2:C" & lastRow), "文具" _
)
🔍 lastRowとは?
データの最終行を取得する方法です。上記例の場合「A列の一番下から上に向かって最初にデータがある行」を見つけます。
これで実行時間が数分から数秒に短縮されました!データがある範囲だけを対象にCountIfsを実行するので、無駄な処理がなくなりましたね。
例えば10万行のデータでテストしたときの比較:
- よくない例:約3分30秒
- 改良版:約2秒 という具合に、驚くほどの差が出ました。
💡 パフォーマンスTips
特に大量データを扱う場合、「必要な範囲だけを処理する」というのは鉄則です。私も最初は気づきませんでしたが、この改善で多くのユーザーさんから「動作が速くなった!」と喜びの声をいただきました。
人事データでの活用例
次は、人事部で実際にあった事例をご紹介します。「部署別の評価Aの人数」と「勤続年数5年以上の優秀者(評価A)の人数」を集計する必要があったんです。
サンプルデータ
![人事データのサンプル](https://rebizru.com/wp-content/uploads/2025/02/c3289fe7f4c78ae6adc8b9a9849b4dc6.png)
実装例2:部署別の評価A人数をカウント
Sub 人事集計()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("人事データ")
'営業部の評価A人数
Dim salesTopCount As Long
salesTopCount = Application.WorksheetFunction.CountIfs( _
ws.Range("C:C"), "営業", _
ws.Range("F:F"), "A" _
)
'結果を表示
Debug.Print "営業部の評価A人数: " & salesTopCount & "名"
End Sub
このコードを実行してみると
![人事集計実行結果](https://rebizru.com/wp-content/uploads/2025/02/c20f5a57736149643da9022569d458e9-1.png)
営業部で評価Aの社員は4名となりました。
こんな感じで各部署の状況が一目で分かります。
![営業部の評価Aは4名](https://rebizru.com/wp-content/uploads/2025/02/5f8665a162387d90e9ad4d0e82d27f0d.png)
実装例3:条件を組み合わせた高度な集計
同じデータで、勤続5年以上で評価がAの人数をカウントしてみます。
Sub 勤続5年以上のA()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("人事データ")
'勤続5年以上かつ評価Aの人数
Dim experiencedTopCount As Long
experiencedTopCount = Application.WorksheetFunction.CountIfs( _
ws.Range("E:E"), ">=5", _
ws.Range("F:F"), "A" _
)
'結果を表示
Debug.Print "勤続5年以上の評価A人数: " & experiencedTopCount & "名"
End Sub
こちらを実行すると
![勤続5年以上のAの実行結果](https://rebizru.com/wp-content/uploads/2025/02/afbc0cf7de15b1c321d69a261b76dcf0-1.png)
勤続5年以上で評価Aの社員は3名いることがわかりました。
![勤続5年以上で評価Aの社員は3名いることが分かった](https://rebizru.com/wp-content/uploads/2025/02/e92dc9ae00dece4f2d5f126340b61846.png)
数値条件のコツ
数値の条件指定では、“>=”(以上)、”<=”(以下)、”>”(より大きい)、”<“(より小さい)が使えます。私も最初は「5年以上を抽出するのにどう書けばいいんだろう…」と悩みましたが、”>= 数値”という書き方で簡単に指定できることが分かりました!
実装例4:より複雑な条件での活用
営業部で30歳以上の評価Aの社員という条件を3つ付けてカウントしてみます。
Sub 営業部かつ30歳以上かつ評価A()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("人事データ")
'営業部かつ30歳以上かつ評価A
Dim seniorTopCount As Long
seniorTopCount = Application.WorksheetFunction.CountIfs( _
ws.Range("C:C"), "営業", _
ws.Range("D:D"), ">=30", _
ws.Range("F:F"), "A" _
)
'結果を表示
Debug.Print "営業部の30歳以上評価A人数: " & seniorTopCount & "名"
End Sub
このコードを実行すると
![営業部で30歳以上の評価Aの社員の実行結果](https://rebizru.com/wp-content/uploads/2025/02/0d7a02758668429e5b69c3a78007e374.png)
このように表示されました。
条件を3つ組み合わせても、このようにシンプルに書くことが出来ました。
![営業部で30歳以上の評価Aの社員は2名でした](https://rebizru.com/wp-content/uploads/2025/02/22e5460e764585389eb1a7366b5b7402.png)
在庫管理での活用例
在庫管理では、商品の発注点管理や倉庫別の在庫状況確認が重要です。私が以前、文具メーカーさんで対応した事例をご紹介します。
サンプルデータ
![在庫データのサンプル](https://rebizru.com/wp-content/uploads/2025/02/7a1f34b506f892bd5bb8be13ec2e0d07.png)
実装例5:発注点(在庫数50個以下)の商品をカウント
Sub 在庫50以下()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("在庫データ")
'在庫50個以下の商品数
Dim lowStockCount As Long
lowStockCount = Application.WorksheetFunction.CountIfs( _
ws.Range("D:D"), "<=50" _
)
'結果を表示
Debug.Print "発注が必要な商品数: " & lowStockCount & "個"
End Sub
実行してみると
![発注点(在庫数50個以下)の商品は4個でした](https://rebizru.com/wp-content/uploads/2025/02/77c1fd6c5fbff7d349c37dbb6291d814.png)
在庫が50個以下の商品は4つとわかりました。これで発注が必要な商品の把握が一瞬でできますね。
![在庫が50個以下の商品は4つだった](https://rebizru.com/wp-content/uploads/2025/02/064397f06fe6441727763f65a8a02c2b.png)
実装例6:倉庫別の特定カテゴリ商品数
東京倉庫の文具カテゴリの商品数をカウントしてみます。
Sub 東京倉庫の文具カテゴリ商品数()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("在庫データ")
'東京倉庫の文具カテゴリ商品数
Dim tokyoStationeryCount As Long
tokyoStationeryCount = Application.WorksheetFunction.CountIfs( _
ws.Range("C:C"), "文具", _
ws.Range("F:F"), "東京" _
)
Debug.Print "東京倉庫の文具商品数: " & tokyoStationeryCount & "点"
End Sub
このコードを実行してみると
![東京倉庫の文具は3点あることが分かった](https://rebizru.com/wp-content/uploads/2025/02/9732c9f134891ce4eb887d466f26ea27.png)
東京倉庫には3点の文具があることがわかりました。倉庫別の在庫構成が一目瞭然ですね!
![東京倉庫の文具は3つあることが分かる](https://rebizru.com/wp-content/uploads/2025/02/bfdfdda77c39535a3411079a8a48b40d.png)
実装例7:価格帯別の在庫状況
1000円以上かつ在庫20個以上の商品数という範囲を指定する方法を見てみましょう。
Sub 金額が1000円以上かつ在庫20個以上の商品数()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("在庫データ")
'1000円以上で在庫20個以上の商品数
Dim highValueStockCount As Long
highValueStockCount = Application.WorksheetFunction.CountIfs( _
ws.Range("E:E"), ">=1000", _
ws.Range("D:D"), ">=20" _
)
Debug.Print "1000円以上かつ在庫20個以上の商品数: " & highValueStockCount & "点"
End Sub
このコードを実行すると
![1000円以上かつ在庫20個以上の商品数が2点だとわかりました。](https://rebizru.com/wp-content/uploads/2025/02/465b871912a8225d9424642745da5061.png)
1000円以上で在庫が20個以上ある商品は2点とわかりました。この情報は在庫金額の管理にも役立ちますよ。
![1000円以上で在庫が20個以上ある商品は2点と分かった](https://rebizru.com/wp-content/uploads/2025/02/67cf9e2af4c4dfb93f54bb37b2ef8460.png)
💡 実務での活用ポイント
こういった集計を定期的に行う場合は、集計結果を別シートに出力して、グラフ化するのがおすすめです。私もこの方法を採用してから、在庫状況の報告が楽になりました。経営層への報告資料作りが格段にスピードアップしましたよ。
FAQ
よく受ける質問をまとめてみました。
Q1: 検索条件を動的に変更するには?
A: 変数を使って条件を設定できます。こんな感じです:
Sub DynamicCountIfs()
'条件を変数で設定
Dim region As String
Dim minAmount As Long
region = Range("A1") '地域(AIセルに「東京」と入力されている)
minAmount = 10000 '最小金額
'変数を使ってカウント
Dim result As Long
result = Application.WorksheetFunction.CountIfs( _
Range("B:B"), region, _
Range("E:E"), ">=" & minAmount _
)
Debug.Print region & "の" & minAmount & "円以上の件数: " & result
End Sub
実行すると「東京の10000円以上の件数: X件」と表示されます。条件を変えたいときは変数(B1セル)の値を変更するだけでOK!
Q2: 大量データを処理する際の注意点は?
A: 以下の3点がポイントです:
- 処理範囲を必要最小限に絞る
Dim lastRow As Long
lastRow = Cells(Rows.Count, "A").End(xlUp).Row
Range ("A2:A" & lastRow) '必要な範囲だけを指定
- オートフィルターを活用する
'オートフィルターを使って必要なデータだけを抽出してからカウント
With ActiveSheet
.AutoFilterMode = False 'フィルターをクリア
.Range("A1").AutoFilter 'フィルターを設定
.Range("A1").AutoFilter Field:=2, Criteria1:="東京" '東京のデータだけを表示
End With
まとめ
いかがでしたか?VBAでのCountIfsは、最初は少し敷居が高く感じるかもしれませんが、基本的なパターンを押さえれば、とても便利な機能です。
特に覚えておいていただきたいポイントは:
- 範囲指定は必要最小限に
- エラー処理は忘れずに
- 日付や数値の形式には注意
まずは簡単な条件から試してみて、徐々に複雑な条件に挑戦していってくださいね。
💡 次のステップ: CountIfsをマスターしたら、次は「配列を使った高速化」や「Dictionaryを使った集計」にもチャレンジしてみてください。別記事で詳しく解説していますよ!
コメント