VBAでデータ削除を効率化する方法

このQ&Aのポイント
  • Excel2007のVBAを使用して、数千行のデータで特定の条件に基づいて行を削除する方法についての質問です。
  • PCスペックが低いため、削除処理に時間がかかっているようです。効率的な方法は存在するのでしょうか?
  • タイトル列を除くA列の値が「d」以外の行を削除したいという要望があります。
回答を見る
  • ベストアンサー

VBAで削除を早くしたいのですが…

Excel2007のVBAです。キー記録を眺めながら四苦八苦しております。 数千行あるデータで、A列が"d"以外の行を削除したいのですが PCスペックが低いせいか、時間がかかってしまいます。 簡単に効率化することは可能でしょうか? よろしくお願いします。 ※1行目はタイトル列、全体行数は可変です。 Sub A05_A列がd以外は削除する() Application.ScreenUpdating = False Dim sh2 As Worksheet Set sh2 = Worksheets("削list") For i = Cells(Rows.Count, "C").End(xlUp).Row To 2 Step -1 If sh2.Cells(i, "A").Value <> "d" Then Rows(i).Delete End If Next Application.ScreenUpdating = True End Sub

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

こんにちは。 とりあえず、1万行のサンプルで試しながら書きました。 削除する行がテーブル下側に纏るように、 一旦ソートしておいてから一括削除します。 多分、この方法がXMLソースの書換え的に楽なんだと思います。 条件付きの他の方法として、  ●[列の非表示]や[グループ化]機能を使っていない場合で、   必ずしも削除する必要がないケースならば、   同じようにテーブル下側に纏めてから   range.ClearContents で消去した方が2割程速いです。 行数や列数等の条件によって、 削除する方法によっての遅速が変わってきますから、 数千件なら、この方法が速いかな?というお話です。 1万行50列のサンプル中不要行40%ランダムに配置 という条件で手許の環境では0.2秒弱でした。 何か不足あれば相談してください。 ' /// Sub Re8937081() Dim rngA As Range Dim rng As Range Dim rngD As Range   With Application     .ScreenUpdating = False     .Calculation = xlCalculationManual     .EnableEvents = False   End With   With Sheets("削list")     If .FilterMode Then .ShowAllData     Set rngA = .Range("B2").CurrentRegion ' テーブル全体をRange型で指定する     With rngA       .AutoFilter field:=1, Criteria1:="<>d" ' A列が"d"以外の行を抽出       Set rng = .Range("A:A")       .Columns(1).Offset(1).ClearContents ' A列が"d"以外のセルすべてをクリア(フラグ)     End With     .AutoFilterMode = False   End With   rngA.Sort Key1:=rng(1), Order1:=xlAscending, Header:=xlYes ' A列が"d"のセルを上部に並べる   On Error Resume Next   Set rngD = rng.SpecialCells(xlCellTypeBlanks) ' A列が"d"以外の行を選択   On Error GoTo 0   If Not rngD Is Nothing Then rngD.EntireRow.Delete '  ' A列が"d"以外の行を一括削除   With Application     .Calculation = xlCalculationAutomatic     .EnableEvents = True     .ScreenUpdating = True   End With   Set rng = Nothing:  Set rngD = Nothing:  Set rngA = Nothing End Sub ' ///

momono14
質問者

お礼

realbeatin様とkagakusuki様のスクリプトは素晴らしく早くて、 思わず笑いが出てしまいました。 realbeatin様のスクリプトは一見長いですが、所々の注釈が 非常にありがたく、修正に対して柔軟性が高いと思い、自分に とってはこちらが「より簡単」ではないかと感じましたので、 BAを差し上げたいと思います。 ありがとうございました。

その他の回答 (4)

  • kagakusuki
  • ベストアンサー率51% (2610/5101)
回答No.5

 回答No.3,4です。 >realbeatin様の方は一見長いですが、所々の注釈が 非常にありがたく との事でしたので、質問者様だけではなく、このサイト利用される他の方々にとっても、今後の参考になる様に、VBAの構文に注釈をつけたものを念の為に投稿致します。 Sub A05_A列がd以外は削除する◆注釈付() 'QNo.8937081 VBAで削除を早くしたいのですが… Dim lr As Long 'データのある最終行の行数を示すための変数の定義 With Sheets("削list") '処理を行うシートを指定 lr = .Cells(Rows.Count, "C").End(xlUp).Row 'C列においてデータのある最終行の行数を取得 If lr < 2 Or Application.WorksheetFunction _ .CountIf(.Range("A2:A" & lr), "<>d") = 0 Then End '↑もしデータのある最終行が2行目よりも上の行であるか、或いは 'A列において「2行目」~「『C列にデータのある最終行』と同じ行」の範囲内に、 '「値が『d』となっていないセル」(空欄のセルも含む)が存在しない場合には、マクロを終了 .Rows("1:" & lr).AutoFilter '1行目を項目名としたオートフィルターモードON .Rows("1:" & lr).AutoFilter Field:=1, Criteria1:="<>d" 'A列の値が「dではない」行のみを選択して表示 .Rows("2:" & lr).Delete '↑オートフィルターによって表示されている行の内、2行目~「C列にデータのある最終行」の範囲内にある行を削除 .Rows("1:" & lr).AutoFilter 'オートフィルターモードの解除 End With End Sub

momono14
質問者

お礼

kagakusuki様 お返事遅れてすみません。 会社に行かないと環境が無かったもので… わざわざ追加の投稿を頂きありがとうございます。 実は、BAを決めた後に「F8で追っかければいいやん」 と当たり前のことを再発見し、自分で細々とコメントを 付けていました。今回の回答は、答え合わせにもなり 安心できました。 ありがとうございました。

  • kagakusuki
  • ベストアンサー率51% (2610/5101)
回答No.4

 回答No.3です。  申し訳御座いません。回答No.3のVBAには、A列が"d"となっている行"のみ"である場合において、2行目以下の全ての行が削除されてしまうという欠陥が御座いました。  以下のVBAは、その欠陥を無くしたものです。 Sub A05_A列がd以外は削除する() 'QNo.8937081 VBAで削除を早くしたいのですが… Dim lr As Long 'データのある最終行 With Sheets("削list") lr = .Cells(Rows.Count, "C").End(xlUp).Row If lr < 2 Or Application.WorksheetFunction _ .CountIf(.Range("A2:A" & lr), "<>d") = 0 Then End .Rows("1:1").AutoFilter .Rows("1:" & lr).AutoFilter Field:=1, Criteria1:="<>d" .Rows("2:" & lr).Delete .Rows("1:1").AutoFilter End With End Sub

momono14
質問者

お礼

realbeatin様とkagakusuki様のスクリプトは素晴らしく早くて、 思わず笑いが出てしまいました。 kagakusuki様のスクリプトは「簡単に効率化」という点では 短くてよいと思います。 しかしながら、realbeatin様の方は一見長いですが、所々の注釈が 非常にありがたく、本質的にはこちらが「より簡単」ではないかと 感じてしまったので、申し訳ないですが今回はrealbeatin様の方に BAを差し上げたいと思います。 訂正版まで上げていただいたのにこのような連絡となり誠に申し訳 ございません。これに懲りずに、また困ったことがありましたら お助けいただけると幸いです。 ありがとうございました。

  • kagakusuki
  • ベストアンサー率51% (2610/5101)
回答No.3

 何もFor~Nextを使って1行ずつ処理せずとも、オートフィルターを使ってA列が"d"以外の行を一気に削除してしまう様にすれば良いのではないでしょうか。  因みに、バージョンがExcel2003以前のExcelの場合は、オートフィルターで仕分けられる限度が1000行までしかありませんでしたが、Excel2007からはその様な限界が無くなったそうです。 Sub A05_A列がd以外は削除する() 'QNo.8937081 VBAで削除を早くしたいのですが… Dim lr As Long 'データのある最終行の行番号 With Sheets("削list") lr = .Cells(Rows.Count, "C").End(xlUp).Row .Rows("1:1").AutoFilter .Rows("1:" & lr).AutoFilter Field:=1, Criteria1:="<>d" .Rows("2:" & lr).Delete .Rows("1:1").AutoFilter End With End Sub

  • t-aka
  • ベストアンサー率36% (114/314)
回答No.2

ソースコードそのものは特に問題ないような印象です。 もしもワークブックに数式が含まれている場合は 再計算を一時的に手動に設定すると処理の高速化が図れます。 Application.Calculation = xlCalculationManual と宣言してください。 処理が終了する時は Application.Calculation = xlCalculationAutomatic として、再計算を自動化しましょう。 あるいは、元データがCSVなどのテキストファイルの場合は Excel上で展開せずに処理すると動作は軽くなります。

momono14
質問者

お礼

xlCalculationManualは、たまにテンプレ的に見かけたのですが 意味が分からずとりあえずは放置…としておりました。 今回の自分の表では計算式はその都度実数化してるのですが、 (次に投げられる予定の)上司の作った表は計算式が多用されておりますので、 きっと未来で感謝させていただくと思います。 お返事ありがとうございました。

関連するQ&A

  • VBAで空白行を削除する

    VBAでリストの空白行を削除するための適当なコードを探しているのですがどんぴしゃのものが中々見つかりません。ご教授下さい。 ブックBのシートBのリストにはA2~AN●まで値が入っています。 別のブックAからVBAで値を取り出し貼り付けています。 いくつかの方法を試しました。 (1)ブックを開いたときに空白行を削除 Sub Auto_Open() '空白行を削除 Dim lRow As Long Dim i As Long lRow = Cells(Rows.Count, 1).End(xlUp).Row Application.ScreenUpdating = False For i = lRow To 2 Step -1 If Cells(i, 1).Value = "" Then Range(i & ":" & i).Delete End If Next i Application.ScreenUpdating = True End Sub 5分以上砂時計のままで結局終わりません。 強制終了させ再度ブックを開くと空白行は削除されているのですが、こんな動作では使うことができません。 (2)ブックAの値を貼り付けた後、空白行を削除し上書き保存する Sub エクスポート() Application.ScreenUpdating = False Application.Calculation = xlCalculationManual Range(Cells(5, 7), Cells(79, 46)).Select Selection.Copy 'コピー Workbooks.Open Filename:="\\パス\ブックB.xlsm" '貼り付け先ファイルオープン Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _ :=False, Transpose:=False '貼り付け Dim lRow As Long Dim i As Long lRow = Cells(Rows.Count, 1).End(xlUp).Row Application.ScreenUpdating = False For i = lRow To 2 Step -1 If Cells(i, 1).Value = "" Then Range(i & ":" & i).Delete End If Next i Application.ScreenUpdating = True  '空白行を削除 ActiveWorkbook.Save '上書き保存 Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True End Sub (3)空白行を削除の部分は以下のコードも試しました Worksheets("SheetB").Range("A1").Select Set currentCell = Worksheets("sheetB").Range("A1") Do While Not IsEmpty(currentCell) Set nextCell = currentCell.Offset(1, 0) If Not IsEmpty(currentCell) Then 'カレントセルが空白でなく、 If IsEmpty(nextCell) Then '次のセルが空白のとき nextCell.EntireRow.Delete End If End If Set currentCell = currentCell.Offset(1, 0) Loop '空白行削除 宜しくお願い致します。

  • VBAで教えてください。

    以前ここで教えていただいたVBAで http://jisaku.155cm.com/src/1371930716_9b9006528605642980beed48a8998013b0731e4b.jpg のようにA列のテスト4をクリックしたときにC列のテスト4が一発で解るようにしたいです。 もちろん、テスト11をクリックしたときは、テスト4塗りつぶしは解除され、 テスト11が塗りつぶされるようにしたいです。 写真は塗りつぶししていますが、解るようにしたいだけなので、塗りつぶしにはこだわっていません。 あと、E、F、G列は解りやすく並べているだけで、実際はA、B、C列だけです。 それと、C列は関数を使って表示してあります。 という質問で Private Sub Worksheet_SelectionChange(ByVal Target As Range) 'この行から Dim i As Long Range("C:C").Interior.ColorIndex = xlNone If Application.Intersect(Target, Range("A:A")) Is Nothing Or Target.Count <> 1 Then Exit Sub On Error Resume Next Application.ScreenUpdating = False ActiveSheet.Cells.interio.ColorIndex = xlNone For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row If Cells(i, "C") = Target Then Cells(i, "C").Interior.ColorIndex = 3 End If Next i Application.ScreenUpdating = True End Sub 'この行まで をシートのコードに張り付ければいいですよ。と教えてくれたものがあるのですが、 A列でクリックした文字をC列からすべて見つけて反転してくれないようです。何個か反転してくれない ものが出てきてしまいました。 C列が何百行とかなってしまうと、すべての同じ文字を検索してくれないのでしょうか? ちなみに列がここに掲載しているものと違うので Private Sub Worksheet_SelectionChange(ByVal Target As Range) 'この行から Dim i As Long Range("R:R").Interior.ColorIndex = xlNone If Application.Intersect(Target, Range("B:B")) Is Nothing Or Target.Count <> 1 Then Exit Sub On Error Resume Next Application.ScreenUpdating = False ActiveSheet.Cells.interio.ColorIndex = xlNone For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row If Cells(i, "R") = Target Then Cells(i, "R").Interior.ColorIndex = 3 End If Next i Application.ScreenUpdating = True End Sub 'この行まで のCをRにAをBに変更して使ってます。 これがいけないのかな? よろしくお願いします。

  • エクセルの行の削除を配列で高速化したい

    A列にID番号(012345等の文字列化した数字) B列に属性(A、B、C等の文字列) C列に数値  のようなデータがあります。 1行目はタイトル行です。 最優先されるキーをA列、2番目に優先されるキーをB列にして並べ替えてあります。 A列、B列のデータは重複するものがあります。 このデータを、 A列のID番号が同じだった場合、上の属性がA、次の行の属性がBの組み合わせだった場合のみ、下の行のC列の数値データを上の行のC列の数値に加算して、下の行を削除します。 以下のマクロを書き、うまくいきました。 Sub 集計() Dim i As Long, r As Long r = Cells(65536, 1).End(xlUp).Row Application.ScreenUpdating = False For i = r To 2 Step (-1) If Cells(i, 1) = Cells(i - 1, 1) Then If Cells(i, 2) = "B" And Cells(i - 1, 2) = "A" Then Cells(i - 1, 3) = Cells(i - 1, 3) + Cells(i, 3) Rows(i).Delete End If End If Next Application.ScreenUpdating = False End Sub しかし、データ数が多いので1分以上かかってしまいます。 多分、配列に取り込んで処理できれば飛躍的に高速化できるとは思うのですが、 V = Range(Cells(2, 1), Cells(r, 3)).Value と取り込んだあと、どう処理したらいいのかわかりません。 教えてください。

  • 重複データーの集計、削除

    どなたかご教授下さい。 下記のようにD列に重複する行があればI列に集計し、行削除するマクロを作成しました。 さらに、重複する基準となる列を複数(D列,F列,G列)に増やしたいのですが、上手く出来ません。 宜しくお願い致します。 Sub test() Dim i, j For i = 19 To Cells(Rows.Count, 2).End(xlUp).row - 1 For j = Cells(Rows.Count, 2).End(xlUp).row To i + 1 Step -1 If Cells(i, 4).value = "" Then Exit Sub If Cells(i, 4).value = Cells(j, 4).value Then Cells(i, 9).value = Cells(i, 9).value + Cells(j, 9).value Rows(j).Delete End If Next Next End Sub

  • VBA 高速化

    以下のコードを改良して早く処理できるようにしたいです。素因数分解をして、素因数の数を数えるプログラムです。 Sub 素因数を数える() Application.ScreenUpdating = False Application.Calculation = xlCalculationManual Dim I As Long, j As Long, cnt As Long, wS As Worksheet, k As Long, Set wS = Worksheets("Sheet2") k = Worksheets("Sheet1").Range("A100010").End(xlUp).Row - 1 For dd = 3 To k Call aaa(Range("A" & dd)) Next dd Application.ScreenUpdating = True Application.Calculation = xlCalculationAutomatic End Sub Private Sub aaa(ByVal Target As Range) Set wS = Worksheets("Sheet2") If Intersect(Target, Range("A:A")) Is Nothing Or Target.Count > 1 Then Exit Sub With Target If Not IsNumeric(.Value) Then Exit Sub If .Value Mod 1 = 0 Then Range("D1") = .Value For I = 1 To wS.Cells(Rows.Count, "A").End(xlUp).Row Do While Cells(Rows.Count, "D").End(xlUp) Mod wS.Cells(I, 1) = 0 cnt = cnt + 1 Cells(Rows.Count, "D").End(xlUp).Offset(1) = Cells(Rows.Count, "D").End(xlUp) / wS.Cells(I, 1) Loop If Cells(Rows.Count, "D").End(xlUp) = 1 Then Exit For Next I End If .Offset(, 1) = cnt End With Range("D:D").Clear End Sub 以前教えていただいたコードを使って書きました。 どういう状況で使っているかといいますと、シート1のA列に自然数を2から順番に並べ、シート2のA列に素数を並べておき、プログラムを実行すると、B列に素数の数が表示されるという具合です。 大変役に立っていたのですが、10萬ほどのデータを扱おうとすると、自分のコンピュータでは時間がかかりすぎます。そこでコードを改良して高速化をしたいのです。 いま考えられる改良点は、 1、D列を使って行っている処理をメモリで行うようにして、セルへのアクセスを省けないか 2、aaaの5行目の、"wS.Cells(Rows.Count, "A").End(xlUp).Row"この処理を簡単な変数の処理で代用できないか ということです。他にも高速化できる方法があれば教えてください。 よろしくお願いします。

  • VBAでの訂正のアドバイスをお願いします。

    下記のコードはテキストファイルを複数選んでA列の最終行に出力するためのものなのですが 今の状態だと出力したデータの空白行が消えてしまっていて次の段階に進めません。 このコードを使う前、テキストファイルを一枚一枚コピー&貼り付けして作業していました。 その場合は空白行もそのままの状態でした。 空白行もそのまま出力するにはどこを変更すればいいのかアドバイスお願いします。 よろしくお願いします。 Sub 連続出力() Dim xFile As Variant, i As Long, sh As Worksheet, bk1 As Workbook xFile = Application.GetOpenFilename(FileFilter:="テキスト ファイル (*.txt), *.txt", MultiSelect:=True) If IsArray(xFile) Then Set sh = ActiveSheet Application.ScreenUpdating = False For i = LBound(xFile) To UBound(xFile) With Workbooks.Open(xFile(i)) .Worksheets(1).Columns(1).SpecialCells(xlCellTypeConstants).Copy If sh.Cells(1).Value = "" Then sh.Cells(1).PasteSpecial xlValues Else sh.Cells(Rows.Count, 1).End(xlUp).Offset(1).PasteSpecial xlValues End If Application.CutCopyMode = False .Close SaveChanges:=False End With Next i Application.ScreenUpdating = False End If End Sub

  • excelマクロについて

    お世話になります。 下記のように間引きしたいのですが、 0.10.20.30,40,50.60→0.100.200 何故か80からスタートしてしまいます。 0.10.20.30,40,50.60→80.180.280 宜しくお願いします。 Sub test() Application.ScreenUpdating = False i = 1 '1行目の意味 mydata = Cells(i, 1) 'A列でデータが存在するか判定 Do Until mydata = "" '空白になるまで繰り返し処理 Rows(i).Resize(9).Delete '9行の削除 i = i + 1 mydata = Cells(i, 1) Loop Application.ScreenUpdating = True End Sub

  • エクセルマクロ行削除

    エクセル2013です。 以下の行削除マクロを作りました。 取得した 最終行が20行目として 最終列がZ列として セル Z20 の値が 1以上なら問題なく動作するのですが セル Z20 の値が 0 だとループして終了しません。 どこを修正しても、思うように動作しません。 どこを修正すれば、いいのでしょうか? よろしくお願いします。 Sub 行削除() Dim 最終行 Dim 最終列 Dim 対象行 最終列 = Cells(8, Columns.Count).End(xlToLeft).Column '8行目の最終列を取得 最終行 = Cells(Rows.Count, 1).End(xlUp).Row 'A列の最終行を取得 Application.ScreenUpdating = False '画面切替停止 For 対象行 = 10 To 最終行 If Cells(対象行, 最終列) = 0 Then Rows(対象行).Delete 最終行 = 最終行 - 1 '削除により最終行が1行減ったので最終行の値を1行減らす 対象行 = 対象行 - 1 '削除により対象行が1行繰り上がったので対象行の値を1行減らす Else End If Next 対象行 Application.ScreenUpdating = True '画面切替停止解除 End Sub

  • 連続して同じ値が入ってるなら削除したいのですが

    指定した値なおかつ連続して同じ値が入ってるなら削除したいのですが A列に 紅葉 紅葉 桜 桜 紅葉 とはいっていて、 Sub Sample() Dim i As Long Dim mystr As String mystr = "桜" For i = Cells(Rows.Count, "A").End(xlUp).Row To 2 Step -1 If Cells(i, 1) = Cells(i - 1, 1) = mystr Then Rows(i).Delete End If Next i End Sub をしても、削除されません。 4行目の桜が削除されてもいいと思うのですが コードのどこが間違えてますか?

  • 指定した範囲で0の行を削除するマクロ

    以下のコードで7列目が0の行を削除するマクロを作ったのですが、 13行目以降を削除するように指定できますでしょうか? 1-12行は別のシートに数式を入れているため、削除したくないのですが、 うまくいきません。よろしくお願いいたします。 Sub 行削除() Dim Rw As Long Dim Cnt As Long Application.ScreenUpdating = False For Rw = Cells(Rows.Count, 7).End(xlUp).Row To 1 Step -1 With Cells(Rw, 7) If .Value = 0 Then .EntireRow.Delete Cnt = Cnt + 1 End If End With Next If Cnt = 0 Then MsgBox "削除対象行は、見つかりません。", vbExclamation Else MsgBox Cnt & " 件見つかり行を削除しました。", vbInformation End If End Sub

専門家に質問してみよう