特定の行だけ削除する


テーブル内の特定行だけ削除するには、どうしたらいいでしょう。ここでは、下図のようなテーブルから、[名前]が"田中"の行だけを削除するケースで考えてみます。

これ、普通のセル範囲だったら、たとえば次のように考えます。

Sub Sample1()
    Dim i As Long
    For i = 10 To 2 Step -1
        If Cells(i, 2) = "田中" Then
            Cells(i, 2).EntireRow.Delete
        End If
    Next i
End Sub

もちろん、これでも成功します。ですがこれは、普通のワークシート上での考え方です。テーブルはExcelが管理する特別なデータベース領域です。

データベース的に考えるのなら、上のようにセルを1つずつ見ていって、それが条件に一致するかどうか…という判定はしません。非効率的だからです。データベース的な発想なら「[名前]フィールドが"田中"であるすべてのレコード(行)」だけを取り出すという操作をするでしょう。いわゆるクエリーを使います。テーブルに対しても、同じアプローチをしましょう。Excelでクエリーといえば、何といってもオートフィルタです。テーブルの[名前]列つまり2列目を"田中"で絞り込みます。

Sub Sample2()
    Range("A1").ListObject.Range.AutoFilter 2, "田中"
End Sub

オートフィルタで絞り込んだ結果のうち「タイトル行を除く実データだけ」を削除したいのですから、このテーブルのDataBodyRangeを操作してやります。ただ、そうなると、オートフィルタをかけるときが"Range"で実データを特定するときが"DataBodyRange"になってしまいます。オートフィルタで絞り込むときも"DataBodyRange"でいけますから、ここは可読性のために統一するといいでしょう。

Sub Sample3()
    Range("A1").ListObject.DataBodyRange.AutoFilter 2, "田中"
    Range("A1").ListObject.DataBodyRange.Select
End Sub

削除します。

Sub Sample4()
    Range("A1").ListObject.DataBodyRange.AutoFilter 2, "田中"
    Range("A1").ListObject.DataBodyRange.EntireRow.Delete
    Range("A1").ListObject.DataBodyRange.AutoFilter 2
End Sub

「Range("A1").ListObject.DataBodyRange」を連呼していて可読性が悪いですから、ここはWithでくくりましょう。

Sub Sample5()
    With Range("A1").ListObject.DataBodyRange
        .AutoFilter 2, "田中"
        .EntireRow.Delete
        .AutoFilter 2
    End With
End Sub

削除するとき、ただ「.Delete」だけでも成功しますが、テーブルではセル単位での挿入や削除が許されていません。常に行(レコード)単位で操作します。したがって、ただ「.Delete」だけだと次の確認メッセージが表示されてマクロが停止します。

なので、ここは「.EntireRow.Delete」と、"行全体"を指定します。なお、最後の「.AutoFilter 2」はオートフィルタの絞り込みを解除しています。普通のワークシートでしたら「.AutoFilter」だけを実行して、オートフィルタ矢印ボタン(▼ボタン)まで消すところですが、テーブルにはもれなくオートフィルタがついてきます。テーブルでは通常オートフィルタ矢印ボタン(▼ボタン)が常に表示されていますので、オートフィルタ自体を解除するのではなく「2列の目の絞り込みだけを解除」します。そのときは、列位置を表す数値だけは指定します。