既に http://oshiete.goo.ne.jp/qa/3705773.html のようなサイトでも類似の質問があり、試してみたのですが。
どうもうまくいきません。
Inputbox等は必要ありませんので、シンプルに「G列に指定のキーワードを含む行があれば、その行すべてを削除する」といったマクロがあればお教えいただきたいのですが。
データは30万件ほどあり結構重い作業になるかもですが…。
前回も似たような質問をしたのですが。 http://q.hatena.ne.jp/1416654240
応用させる実力がまだありませんでして…よろしくお願い致します。
まともに行削除をすると数分オーダーなので、削除を一度にする例です。
セルの結合等あるとできないので、そのときは0ポイント配分で結構です。
作業列としてZ列を使用しているので、データがZ列以降にもある場合は、
コード中のZを十分大きな列名に変更してください。
30万行のデータで約3秒でした。
Option Explicit Sub Main() Dim st st = Timer() DeleteRow "りんご", "G" Debug.Print Timer() - st End Sub Sub DeleteRow(keyWord As String, searchCol As String) Const DelNum = 9999999 Const WorkCol = "Z" Dim lastRow As Long lastRow = Cells(Rows.Count, searchCol).End(xlUp).Row Dim kt kt = Cells(1, searchCol).Resize(lastRow) Dim st st = Cells(1, WorkCol).Resize(lastRow) Dim r As Long For r = 1 To lastRow If InStr(kt(r, 1), keyWord) = 0 Then st(r, 1) = r Else st(r, 1) = DelNum End If Next Cells(1, WorkCol).Resize(lastRow) = st ActiveSheet.Sort.SortFields.Clear ActiveSheet.Sort.SortFields.Add _ Key:=Cells(1, WorkCol).Resize(lastRow), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal With ActiveSheet.Sort .SetRange Range("A1").Resize(lastRow, Cells(1, WorkCol).Column) .Header = xlGuess .Orientation = xlTopToBottom .SortMethod = xlPinYin .Apply End With Dim f As Range Set f = Columns(WorkCol).Find(DelNum, lookat:=xlWhole) If Not f Is Nothing Then Rows(f.Row & ":" & lastRow).Delete Columns(WorkCol).ClearContents End Sub
こんな感じで、どうでしょうか。
Const SPEED_UP = False ' True で速くなる Const MAX_ROW = 300000 ' 突っ走るのが怖いので Const KEYWORD = "りんご" Sub Delete_Row_Include_Keyword() On Error GoTo ErrorHandler If SPEED_UP Then 'ワークシートに描画しない Application.ScreenUpdating = False End If r = 1 Do While r < MAX_ROW Set c = Cells(r, 7) If IsEmpty(c) Or c.Value = "" Then Exit Do End If If InStr(c.Value, KEYWORD) > 0 Then c.EntireRow.Delete Else r = r + 1 End If Loop FINAL: If SPEED_UP Then '結果を描画する Application.ScreenUpdating = True End If Exit Sub ErrorHandler: GoTo FINAL End Sub
行を削除したいシートを選択した状態で、このサブルーチンを実行してください。
先頭の方にある KEYWORD を、適当に変えてください。
G列のセルが、空の行が出てくると、そこで止まります。
処理が延々と終了しないのは、ちょっと恐いので、行数のカウントで最大の行数も指定してます。
SPEED_UP という定数を True にすると、画面の描画を止めるので、少し早くなります。
中程度のノートブックで、2500行くらいで 0.5秒くらいです。
それでも、30万行もあると、パソコンの性能にもよりますが、数分かかると思います。
バックアップを取ってから、試してみてください。
「ThisWorkBook」というので動かすと何も起きず。
「標準モジュール」で動かすと「型が一致しません」と出てきます。
回答では書き足りなかったのですが、マクロは「標準モジュール」で動作します。
んで、「型が一致しません」についてなのですが、もしかしたらキーワードを探す G列が数式になってないでしょうか?
試した感じでは、G列にエラーになっているセルがあると「型が一致しません」となります。
#REF! とか #DIV/0! とか。
もし、対象のシートがそのようになっているのであれば、エラーになっているセルがあったときに、
のどちらにするか決められるのであれば、マクロで処理ができると思います。
エラーのある行を削除して実行しました。
でも動かなかったんですが・・・G列の1行目と2行目が空白セルだったので、ここにデータを入れてから実行したら、うまくマクロが稼働しました!(88215行目で止まりましたが……データは入ってました)
ありがとうございましたm(_ _)m
こんな感じでしょうか。
Public Sub DeleteRow()
Dim KeyWord As String
Dim R As Long
Dim MaxRow As Long
KeyWord = "er" '削除の条件
'G列がキーなのでG列で最終行を取得する
MaxRow = Range("G" & Cells.Rows.Count).End(xlUp).Row
'最後の行から1行目まで後ろからループさせることで読み飛ばしを回避する
For R = MaxRow To 1 Step -1
If Range("G" & R) = KeyWord Then
Rows(R).Delete
End If
DoEvents
Next
End Sub
1行目から順に・・・とすると削除すると行がずれてしまうので、後ろから順にまわすのがセオリーです。
部分一致です!「#NAME?」と「#N/A」を消してやってみたら、やはり「実行中」とは出てくるんですが、マクロが動作しているときのWindows7の青丸がぐるぐるしている状態ではなく、動作していない白い十字の状態にすぐなってしまいます。
でもご回答いただきまして、ありがとうございます!
部分一致の場合、If文の行を次のようにしてください。
If Instr(Range("G" & R),KeyWord)>0 Then
また、DoEventの前の行か後の行に次の行を追加してください。
Application.StatusBar = R & " / " & MaxRow
実行中はステータスバーに進行状況が表示されます。
そうそう、速くするには Application.ScreenUpdating = Falseにしておきましょう。 DoEventsで「応答なし」を回避しています。毎回のループではおおすぎるのならDoEventsの行を次のようにしてもいいでしょう。
If R Mod 100 = 0 Then
DoEvents
Application.StatusBar = R & " / " & MaxRow
End If
100行ごとにDoEventsとステータスバーへ進行状況のメッセージを書き込みます。
条件も「含む」であるなら Like とかInstrとかを使って書き直す必要があります。
まともに行削除をすると数分オーダーなので、削除を一度にする例です。
セルの結合等あるとできないので、そのときは0ポイント配分で結構です。
作業列としてZ列を使用しているので、データがZ列以降にもある場合は、
コード中のZを十分大きな列名に変更してください。
30万行のデータで約3秒でした。
Option Explicit Sub Main() Dim st st = Timer() DeleteRow "りんご", "G" Debug.Print Timer() - st End Sub Sub DeleteRow(keyWord As String, searchCol As String) Const DelNum = 9999999 Const WorkCol = "Z" Dim lastRow As Long lastRow = Cells(Rows.Count, searchCol).End(xlUp).Row Dim kt kt = Cells(1, searchCol).Resize(lastRow) Dim st st = Cells(1, WorkCol).Resize(lastRow) Dim r As Long For r = 1 To lastRow If InStr(kt(r, 1), keyWord) = 0 Then st(r, 1) = r Else st(r, 1) = DelNum End If Next Cells(1, WorkCol).Resize(lastRow) = st ActiveSheet.Sort.SortFields.Clear ActiveSheet.Sort.SortFields.Add _ Key:=Cells(1, WorkCol).Resize(lastRow), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal With ActiveSheet.Sort .SetRange Range("A1").Resize(lastRow, Cells(1, WorkCol).Column) .Header = xlGuess .Orientation = xlTopToBottom .SortMethod = xlPinYin .Apply End With Dim f As Range Set f = Columns(WorkCol).Find(DelNum, lookat:=xlWhole) If Not f Is Nothing Then Rows(f.Row & ":" & lastRow).Delete Columns(WorkCol).ClearContents End Sub
黄色くなったときに、r と keyWord、それから LasrRow の値は何でしょうか。
また G列の r 行にはどのようなデータがあったでしょうか。
変数の中身は、マウスカーソルを変数の上に持っていけば確認できます。
あ、知らなかったです、確かにマウスカーソルを持っていったらr=77643行目がヒットしておりまして、そこに「#NAME?」と記載されてました!
消してもう1回やると、次は132329行目に「#N/A」とありました。
それも消して、もう1回やると・・・うまくいきました!
ありがとうございますヽ(´▽`)/
黄色くなったときに、r と keyWord、それから LasrRow の値は何でしょうか。
2015/02/28 15:16:54また G列の r 行にはどのようなデータがあったでしょうか。
変数の中身は、マウスカーソルを変数の上に持っていけば確認できます。
あ、知らなかったです、確かにマウスカーソルを持っていったらr=77643行目がヒットしておりまして、そこに「#NAME?」と記載されてました!
2015/03/01 20:47:03消してもう1回やると、次は132329行目に「#N/A」とありました。
それも消して、もう1回やると・・・うまくいきました!
ありがとうございますヽ(´▽`)/