和風スパゲティのレシピ

日本語でコーディングするExcelVBA

条件を満たす行を削除する - Delete/Union

特定の条件を満たす行(データ)を削除する方法を解説します。

For文でStep-1を利用して最終行から1行ずつ削除していく方法と、
Unionメソッドで一つのRangeオブジェクトにして一括削除する方法があります。


今回はサンプルとして、以下のようなデータの中で、
「みかん」や「12月のみかん」を削除するコードを解説します。

対象データ

For文で1行ずつ削除する方法

まずはFor文で1行ずつ削除する方法がこちらです。

Sub 特定の条件を満たす行を削除_For文()

    Dim ws処理シート As Worksheet
    Set ws処理シート = Worksheets("データ")
    
    Dim 最終行 As Long
    最終行 = ws処理シート.UsedRange.Row + ws処理シート.UsedRange.Rows.Count - 1

    Dim R As Long
    For R = 最終行 To 2 Step -1

        If ws処理シート.Cells(R, 7) = "みかん" Then
            ws処理シート.Rows(R).Delete
        End If
        
    Next

End Sub

 
行の削除は「Rows(行番号).Delete」で実行が可能です。

問題は行の削除を実行すると行番号がズレてしまう点で、
通常のFor文ではこの処理は正しく動きません。


例えば3,4行目に連続して「みかん」が現れた場合、

  • 3行目が「みかん」なので削除される
  • 4行目だったものが3行目にスライドする
  • 次の判定は4行目、これはもともと5行目だったもの
  • 4行目のみかんは削除されず残ってしまう

という問題が発生します。


これを避けるために、行を削除するコードを書く際は、
Step -1を指定し最終行から上に向かって逆順にループしてください。

複数の条件を判定する場合

「12月かつ商品がみかん」など複数の条件を指定する場合は、
判定コードを「And」や「Or」で重ねてください。

If ws処理シート.Cells(R, 4) = 12 And ws処理シート.Cells(R, 7) = "みかん" Then
    ws処理シート.Rows(R).Delete
End If

 

Unionを使用して一括削除する方法

続いてUnionメソッドを用いて一括削除する方法です。

この方法であれば上記のように逆順でループする必要もない上、
処理速度も高速です。


コードを書くのが多少面倒ではありますが、
For文で速度面に問題が出たらこちらのコードを採用してください。

Sub 特定の条件を満たす行を一括削除()

    Dim ws処理シート As Worksheet
    Set ws処理シート = Worksheets("データ")
    
    Dim 最終行 As Long
    最終行 = ws処理シート.UsedRange.Row + ws処理シート.UsedRange.Rows.Count - 1
    
    Dim rows削除行 As Range
    Dim R As Long
    For R = 2 To 最終行

        If ws処理シート.Cells(R, 7) = "みかん" Then
            If rows削除行 Is Nothing Then
                Set rows削除行 = ws処理シート.Rows(R)
            Else
                Set rows削除行 = Union(rows削除行, ws処理シート.Rows(R))
            End If
        End If
        
    Next
    
    If Not rows削除行 Is Nothing Then
        rows削除行.Delete
    End If

End Sub

 
Unionメソッドを使用すると、Rangeオブジェクト同士を結合し、
ひとつのRangeオブジェクトにする
ことができます。


これを利用して削除する行をRangeオブジェクトに貯めていき、
全データの判定が終わってから一括削除を実行しています。


例えばループ後にAddressを確認してみると、

Debug.Print rows削除行.Address
' $4:$5,$7:$7,$10:$12

このように複数行がひとつのRangeオブジェクトに格納されているのが分かります。

後はこれを.Deleteで削除すればよいわけですね。


Unionメソッドで注意しなければいけないのが、
引数にNotingを渡すとエラーになってしまう点です。


以下のようにNotingであればUnionを使用しない分岐を書いておかないと、
第1実行時にエラーとなってしまうためご注意ください。

If rows削除行 Is Nothing Then
    Set rows削除行 = ws処理シート.Rows(R)
Else
    Set rows削除行 = Union(rows削除行, ws処理シート.Rows(R))
End If

 

以上で特定の条件を満たす行を削除する方法の解説を終わります。

速度面ではUnionによる一括削除が勝りますが、
Step-1方式の方がコーディングが楽というメリットがあります。


普段はFor文で書き、速度面で気になったらUnionを使用するなど、
状況に応じて使い分けてください。