• ベストアンサー

エクセルVBAについて質問です。

現在、マクロで重複データを削除する処理しています。 一応動作はするのですが、すごく遅いです。 およそ私のPC(XPのQuadコア)で1行処理するのに約0.85秒かかっています。 データが1万行以上もあるようなときは、何時間もかかってしまいます。 エクセルのデータは、以下のように、 A列とB列に文字列が何行にも渡って入っているものです。 A列   B列 AAA BBB CCC DDD EEE FFF GGG BBB CCC HHH CCC DDD (以下同様) 上のようなシートで、A列とB列の両方について重複する行を削除したいと思っています。 上記例だと、一番最後の「CCC-DDD」の箇所を削除したいです。 そこで以下のようなマクロを組みました。 (1)はじめに重複をチェックする変数(A列・B列)を取得します。 (2)上から順にチェックを開始します。 (3)A列・B列双方が取得した変数と一緒なら重複カウンターに1を加える。 (1回目の出現では削除しない) (4)チェックを続け、重複カウンターが2以上になった行は削除する。 (5)上記を空白行まで繰り返す。 というような流れです。 (マクロ記述の途中部分からです) '重複する行を削除 counter3 = 1 Do search_word1 = Cells(counter3, 1).Value search_word2 = Cells(counter3, 2).Value counter4 = 1 double_counter = 0 Do If Cells(counter4, 1).Value = search_word1 And Cells(counter4, 2).Value = search_word2 Then double_counter = double_counter + 1 If double_counter > 1 Then '二度以上出現した場合から削除する Cells(counter4, 1).EntireRow.Delete counter4 = counter4 - 1 End If End If counter4 = counter4 + 1 Loop Until Cells(counter4, 1).Value = "" counter3 = counter3 + 1 Loop Until Cells(counter3, 1) = "" 初心者なのもので、冗長や不適切な箇所などあるかと思います。 より効率的、あるいは、より早くできる書き方がありましたら、 ぜひともお教え下さい・よろしくお願いします。

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

  • ベストアンサー
  • nattocurry
  • ベストアンサー率31% (587/1853)
回答No.1

データをソートすれば、重複データは必ず上下に隣接することになるので、チェック回数を減らすことが出来ます。 データの並び順を変えたくないのであれば、新たにID列を設けて、上から順に連番を振っておき、A列とB列を基準にソートしてから重複行を削除して、最後にID順でソートし直せば良いです。

westnorth1
質問者

お礼

皆様、ご回答ありがとうございました。 お礼が遅れて大変申し訳ありません。 皆様の回答を参考に検討した結果、 nattocurry様のご回答が一番分かりやすかったので、 並べ替えをしてから、隣接する重複レンジを削除するものにしましたら、 実用的な時間で終わるようにすることができました。 ご丁寧なご回答感謝しております。 今後もよろしくお願いします。

その他の回答 (4)

回答No.5

マクロを組む前にデータ側で一手間掛けてはどうですか。 まず、C列に[=Ai&Bi],D列に[=COUNTIF(C$1:Ci,Ci)]と入力し、全データ分へコピー貼付します。 そして、D列の値が>1を検索し、削除するマクロを組めば、スピードアップは確実です。

westnorth1
質問者

お礼

皆様、ご回答ありがとうございました。 お礼が遅れて大変申し訳ありません。 皆様の回答を参考に検討した結果、 並べ替えをしてから、隣接する重複レンジを削除するものにしましたら、 実用的な時間で終わるようにすることができました。 ご丁寧なご回答感謝しております。 今後もよろしくお願いします。

  • nda23
  • ベストアンサー率54% (777/1415)
回答No.4

自動更新、自動計算、イベントの抑止は#1の方の指摘通りです。 重複データの見つけ方ですが、ADOを使う方法があります。 Dim P, C, Q, S, A, B, K, L, X, Y, Z '自身のパス名を取得 P = ThisWorkbook.Path If Right(P, 1) <> "\" Then P = P & "\" P = P & ThisWorkbook.Name 'ADO接続を作成 Set C = CreateObject("ADODB.Connection") C.Provider = "Microsoft.Jet.OLEDB.4.0" C.Properties("Extended Properties") = "Excel 8.0" C.Open P '対象シートの設定 Set S = ThisWorkbook.WorkSheets(1) '最初のシートの場合 'SQLとクエリ作成 ★"A列","B列"は列見出しで、実名に変えて下さい P = "SELECT A列,B列,COUNT(*) AS 件数 FROM [" & S.Name & "$] " _  & "GROUP BY A列,B列 HAVING COUNT(*)>1" Set Q = C.Execute(P) Do Until Q.EOF 'EOFになるまでのループ   A = Q.Fields(0).Value   B = Q.Fields(1).Value   K = Q.Fields(2).Value   '先頭から検索する   Set X = S.Columns("A:A").Find(What:=A, After:=S.Cells(2, 1)) )   Do     '次の行を検索     Set X = S.Columns("A:A").FindNext(After:=X)     L = X.Row '行位置     If S.Cells(L, 2) = B Then       '削除対象行を削除       Y = CStr(L)       S.Rows(Y & ":" & Y).Delete       K = k - 1     End If   Loop Until K = 1   '次のデータ   Q.MoveNext Loop Q.Close C.Close ポイントは以下の通りです。 (1)重複しているデータのみを収集する (2)Findメソッドで対象を探す(セルをグルグルするより断然速い) ただ、行数が少ない場合はクエリの時間がかかるので、素朴な方法の 方が速い場合もあります。何かの参考になれば幸いです。

westnorth1
質問者

お礼

皆様、ご回答ありがとうございました。 お礼が遅れて大変申し訳ありません。 皆様の回答を参考に検討した結果、 並べ替えをしてから、隣接する重複レンジを削除するものにしましたら、 実用的な時間で終わるようにすることができました。 初心者なもので、ご回答の内容がいまいちつかめませんでしたが、 ご丁寧なご回答感謝しております。 今後もよろしくお願いします。

  • AKARI0418
  • ベストアンサー率67% (112/166)
回答No.3

Excelのプロパティを操作することで実現できます。 共通していえることですが、必ず解除してから終わってください、画面が真っ白のままになったりします。もし解除できずに終わってしまいましたら、あわてず解除専用マクロを組んで解除してください。 1.表示の更新を自動で行わないようにする。 Application.ScreenUpdating = false 処理 Application.ScreenUpdating = true 2.セル内の計算を自動で行わないようにする。 Application.Calculation = xlCalculationManual 処理 Application.Calculation = xlCalculationAutomatic 3.イベント発生の抑止 Application.EnableEvents = False 処理 Application.EnableEvents = true お勧めは1と2を組み合わせて使うと速度が大幅に改善されます。 当初のマクロに組み込んで試してみてください、違いが実感できると思います。 Application.ScreenUpdating = false Application.Calculation = xlCalculationManual 処理 Application.ScreenUpdating = true Application.Calculation = xlCalculationAutomatic ソースの組み方としてはまずチェック対象をオブジェクトにセットすることです。 これにより参照先の特定の回数が減り高速化されます。 例 dim rng as Range Set rng = Range(Cells(1, 1), _ Range(ActiveSheet.Cells(65536, 2), _ ActiveSheet.Cells(65536, 2)).End(xlUp)) search_word1 = rng.Cells(counter3, 1).Value となります。 Scripting.Dictionaryを使用しループ回数を減らします。 Microsoft.Scripting.Runtimeを参照設定すること Dim List As New Scripting.Dictionary これは重複データをはじくことができます。 'すでに名前が登録されているかをチェック strBuf = Cells(counter3, 1).Value & "," & Cells(counter3, 2).Value If List.Exists(strbuf) = False Then List.Add(strbuf,"今回はアイテムは使用しません") Else Cells(counter4, 1).EntireRow.Delete End if

westnorth1
質問者

お礼

皆様、ご回答ありがとうございました。 お礼が遅れて大変申し訳ありません。 皆様の回答を参考に検討した結果、 並べ替えをしてから、隣接する重複レンジを削除するものにしましたら、 実用的な時間で終わるようにすることができました。 ご丁寧なご回答感謝しております。 今後もよろしくお願いします。

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.2

Excelに重複行の削除をやらせてしまってはどうでしょう A/B列のデータ範囲の冒頭に題目を記述 DATA-A DATA-B などと D/E列に同様に DATDA-A DATA-Bと記述 A/B列のどこかのセルを選択して CTRL+(テンキーの)* メニューから データ > フィルター > フィルターのオプションの設定 指定した範囲を選択 検索条件範囲を D1:E1 抽出範囲を D1:E1 重複するレコードを無視するのチェックをONにして OKをクリック といった手順をマクロの記録などを使ってみましょう

westnorth1
質問者

お礼

皆様、ご回答ありがとうございました。 お礼が遅れて大変申し訳ありません。 皆様の回答を参考に検討した結果、 並べ替えをしてから、隣接する重複レンジを削除するものにしましたら、 実用的な時間で終わるようにすることができました。 ご丁寧なご回答感謝しております。 今後もよろしくお願いします。

関連するQ&A

  • エクセルVBA 配列の書き方とセルへの一括表示方法

    エクセルのVBAで 下記のようなプログラムを作成しています。 1行目はタイトル行で E列が空白になるまで、 各行のE列~H列の値を変数に入れて、 最後に一括で別の列・行にそれぞれの値を表示・書込したいと思ってますが、 どうもVBAは初めてでよくわかりません。 Dim aaa As String Dim bbb As String Dim ccc As String Dim eee As Double intRow = 2 Do Until Cells(intRow, 5).Value = "" aaa = Cells(intRow, 5).Value) bbb = Cells(intRow, 6).Value) ccc = Cells(intRow, 7).Value) ddd = Cells(intRow, 8).Value) intRow = intRow + 1 Loop aaaの各変数を2行目のA1~intRowまで bbbの各変数を2行目のB1~intRowまで cccの各変数を2行目のC1~intRowまで dddの各変数を2行目のD1~intRowまで セルに一括して表示したいのです。 配列の書き方と、セルの範囲に表示・書込する方法を どうかご教示下さい。お願いいたします。

  • エクセルVBA

    A列を基準にBC列が空白ならAの数値を入れて、A>BならB列を更新、A<CならC列を更新 A列が数値以外ならその行をスキップ、という処理をしたいのですが Option Explicit Dim A As Range, B As Range, C As Range Dim i As Long Sub test() For i = 1 To 10 Set A = Cells(i, 1) Set B = A.Offset(0, 1) Set C = A.Offset(0, 2) If IsNumeric(A) Then Else Exit Sub End If If B.Value = "" Then B.Value = A.Value If C.Value = "" Then C.Value = A.Value If A.Value > B.Value Then B.Value = A.Value If A.Value < C.Value Then C.Value = A.Value Next i End Sub とすると数値以外の行の時点で停止してしまいます。 その行を飛ばして次の行に進むにはどうしたらいいのでしょうか?

  • 【少し急いでます】エクセルについて教えてください!

    Excel2000を使っています。 A列に重複するデータがあり、B列に別データがあります(20000行強) 例)     A  B 1  001 aaa 2   001 bbb 3   001 ccc 4   002 aa 5  002 bb 6  003 aaa 7  003 bbb 8  004 ddd 9   004 eee 10  005 aa 11  006 bbb A列で重複する001は3行あり、重複しているデータは1行にまとめてB列のaaa、bbb、cccをつなげたいです。(わかりづらくてすみません) 例)     A      B 1  001  aaa・bbb・ccc 2  002   aa・bb 3  003  aaa・bbb というようにまとめたいです。 どのような方法がありますでしょうか? よろしくお願い致します。

  • VBAで特定の値がある行を連続コピーしたい

    Excel 2003 OS XP Professional SP3 VBAは自分でコードは組むことはできませんので見よう見まねでやっているレベルです。 A B C D E の列があり、行の1行目はタイトル行になっています。  A  B  C   D  E ***  ***  ***  ***  *** ’  AAA  BBB  CCC  DDD 111 222 333 '   EEE  FFF  GGG  HHH '   III  JJJ  KKK  LLL 444 555 '   MMM  NNN  OOO  PPP A列にカンマがある行にはB~E列に値が入力されていて、A列にカンマ以外の値が入力されている 場合にはB~Eには何も入力されていません。 A列にカンマ以外の値の時、カンマのある行のデータを次のカンマのある行までフィルハンドルをドラッグしてコピーするよう にしたいです。  A  B  C   D  E ***  ***  ***  ***  *** ’  AAA  BBB  CCC  DDD 111  AAA  BBB  CCC  DDD 222  AAA  BBB  CCC  DDD 333  AAA  BBB  CCC  DDD '   EEE  FFF  GGG  HHH '   III  JJJ  KKK  LLL 444  III  JJJ  KKK  LLL 555  III  JJJ  KKK  LLL '   MMM  NNN  OOO  PPP   sub 連続コピー() Dim r As Long Dim n As Long r = 2 n = r + 1 Do While Worksheets("sheet1").Cells(r, 1) <> "" If Worksheets("sheet1").Cells(r, 1).Value = Worksheets("sheet1").Cells(n, 1).Value Then r = n n = n + 1 Else Range(Cells(r, 2), Cells(r, 5)).Copy Range(Cells(n, 2), Cells(n, 5)) n = n + 1 End If Loop End Sub 自分なりに考えてみましたが、ぜんぜん動きません。 どなたかご教授をお願いします。

  • Excel VBAでIF~Thenの入れ子がうまくできません。

    いつもお世話になってます。 IF~Then~EndIfにIFを入れていますがうまくいきません。よろしくお願いします。 Private Sub CommandButton10_Click() Dim i As Long Dim 最終行 As String Dim サーチ行 As Long Dim 行 As Long Dim 列 As Long If TextBox33.Value = "" Then MsgBox "使用量を入力してください。" Else If TextBox11 <> "" Then TextBox26 = TextBox33 * TextBox11 / 100 '成分1 End If If TextBox12 <> "" Then TextBox25 = TextBox33 * TextBox12 / 100 '成分2 End If Workbooks.Open Filename:=ThisWorkbook.Path & "\データ物質試薬管理.xls" Sheets("shinki").Activate 最終行 = (Range("B2").End(xlDown).Row) '商品名の行検索 サーチ行 = 0 For i = 2 To 最終行 If ComboBox3.Value = Range("B" & i) Then Workbooks("データ物質試薬管理.xls").Close savechanges:=False '保存しない Workbooks.Open Filename:=ThisWorkbook.Path & "\データ物質試薬管理.xls" Sheets("kongou").Select Range("A65536").End(xlUp).Offset(1).Select 行 = ActiveCell.Row 列 = ActiveCell.Column Cells(行, 列) = UserForm11.TextBox16.Value 'CAS Cells(行, 列 + 1) = UserForm11.TextBox21.Value '使用日 Cells(行, 列 + 2) = UserForm11.TextBox29.Value '使用者 Cells(行, 列 + 4) = UserForm11.TextBox26.Value '成分1使用量 Cells(行 + 2, 列) = UserForm11.TextBox18.Value 'CAS Cells(行 + 2, 列 + 1) = UserForm11.TextBox21.Value '使用日 Cells(行 + 2, 列 + 2) = UserForm11.TextBox29.Value '使用者 Cells(行 + 2, 列 + 4) = UserForm11.TextBox24.Value '成分3使用量 Cells(行 + 2, 列 + 5) = UserForm11.TextBox32.Value '種類 Cells(行 + 2, 列 + 6) = UserForm11.TextBox34.Value '単位 Cells(行 + 2, 列 + 7) = UserForm11.ComboBox3.Value '商品名 Workbooks("データ物質試薬管理.xls").Close savechanges:=True 'showhinに在庫管理する Workbooks.Open Filename:=ThisWorkbook.Path & "\データ物質試薬管理.xls" Sheets("showhin").Select Range("A65536").End(xlUp).Offset(1).Select 行 = ActiveCell.Row 列 = ActiveCell.Column Cells(行, 列) = UserForm11.TextBox2.Value '品名コード Cells(行, 列 + 1) = UserForm11.ComboBox3.Value '商品名 'Cells(行, 列 + 2) = UserForm9.TextBox3.Value '1本の量 'Cells(行, 列 + 3) = UserForm9.TextBox4.Value '本数 Cells(行, 列 + 4) = UserForm11.TextBox34.Value '単位 Cells(行, 列 + 5) = UserForm11.TextBox32.Value '種別 Cells(行, 列 + 6) = UserForm11.TextBox21.Value '使用日 Cells(行, 列 + 7) = UserForm11.TextBox29.Value '使用者名 Cells(行, 列 + 9) = UserForm11.TextBox33.Value '使用量 Workbooks("データ物質試薬管理.xls").Close savechanges:=True MsgBox "登録しました。" End If サーチ行 = i Exit For 'End If Next If サーチ行 = 0 Then MsgBox ComboBox3.Value & "商品は登録されておりません。" & Chr(10) & "「新規商品登録」ボタンから入力してください。" End If End If If TextBox21.Value = "" Then '使用量 MsgBox "使用日を入力してください。" End If ComboBox3.SetFocus End Sub

  • Excel VBAでのテキスト出力について

    excel vbaでの文字列出力について エクセルからテキスト(メモ帳とか)に出力したいのですが 下記のように出力できなくて困っております。 どなたか教えてほしいです。 ●入力エクセル AAA BBB CCC DDD EEE セル(1,1)~(1,5)にそれぞれ文字列が入っている状況です。 これを下記のように出力したいのです。 ●テキスト出力 "AAA","BBB",CCC,"DDD",EEE CCCとEEEをダブルクォーテーションを付けないで出力したいのです。 出力の方法でwriteとprintがありますが writeで Write #1, Cells(1,1),Cells(1,2),Cells(1,3),Cells(1,4),Cells(1,5) やると、自動で全ての文字がダブルクォーテーションで囲まれて、カンマが自動でつき "AAA","BBB","CCC","DDD","EEE" のようになってしまします。CCCとEEEのダブルクォーテーションが不要です。 printで Print #1, CStr(Cells(1,1)), & "," CStr(Cells(1,2)), & "," Cells(1,3), & "," CStr(Cells(1,4)), & "," Cells(1,5) とすると "AAA", "BBB", CCC, "DDD", EEE となり、カンマの後ろに空白が何個か入った状態になります。 (ブラウザでは空白が分かりづらいですが、テキストですと入っております。) Trim関数でTrim(",")とか色々試しましたが上手くいきません。 どうしたら望み通りの出力ができるでしょうか。 ぜひ教えて頂きたいです。 よろしくお願いします。

  • エクセルVBAについての質問です。

    エクセルVBAについての質問です。 A列のCという商品名が入った列を削除したい場合下記のようにすれば可能かと思いますが、C列のCという商品名が入った列を削除したい場合どのようにすればよいか教えて下さい。 VBAに関してまだ初心者ですがどうぞよろしくお願いします。 行 = 1 Do 行 = 行 + 1 If Cells(行, 1) = "" Then Exit Do End If '行の値がC以外の時は次の行に移る Do If Cells(行, 1) = "C" Then Rows(行 & ":" & 行).Select Selection.Delete Shift:=xlUp Else Exit Do 'ジャンプ先は内側のDo~Loopのすぐ下 End If Loop 'ジャンプ先はここ If Cells(行, 1) = "" Then Exit Do End If Loop End Sub

  • 重複行を完全削除するエクセルのマクロ

    Sub sakujyo() Dim i, ii As Long For i = 1 To Range("a65336").End(xlUp).Row For ii = Range("a65336").End(xlUp).Row To i + 1 Step -1 If Cells(i, 2).Value = Cells(ii, 2).Value _ And Cells(i, 4).Value = Cells(ii, 4).Value _ And Cells(i, 5).Value = Cells(ii, 5).Value Then Dim iii As Byte iii = 1 Rows(ii).Delete Shift:=xlUp End If Next ii If iii = 1 Then Rows(i).Delete Shift:=xlUp iii = 0 Next i End Sub データーが下の表のように入っております。     A    B    C    E    F 1  1/26  a1234  fdsa  5000  C1 2  1/27  a4567  sdfa  4000  T2 3  1/28  a1234  dfsa  5000  C1 4  1/30  b4567  asdf  6600  A2 5  2/10  b4567  fsda  6600  A2 6  2/10  a1234  afds  5000  C1 B列、E列、F列が完全一致(重複1行目と3行目と6行目・4行目と5行目)で削除し結果的に2行目だけ残る方法がしたいのですが、このマクロですと少ないデータですとうまく動くのですが、『大量のデータを一気に削除出来ない』、『同じ重複が3つ以上のデータが多数ある場合データが削除されずに残ってしまう』エラーが出てしまいます。どうかお教えください。

  • EXCEL VBA 

    Excel VBAで アンケート集計をしたいと思い、プログラムを作ったのですが、J列までは入力がうまくいくのですが、K列にデータを入れて次の行にデータを入れると もともと存在していたKれつのデータが消えてしまします。 どう修正すれば ちゃんとデータが残ってくれるのでしょうか?  誰か教えてください Option Explicit Private Sub UserForm_Initialize() Dim チェックボックス As Control With cboBlood .AddItem "A型" .AddItem "B型" .AddItem "O型" .AddItem "AB型" End With cboBlood.ListIndex = -1 txtNo.Value = WorksheetFunction.Max( _ [Database].Resize(, 1)) + 1 txtNo.Enabled = False txtName.Text = "" optMale.Value = True txtAge.Value = 0 For Each チェックボックス In fraOS.Controls チェックボックス.Value = False Next txtName.SetFocus End Sub Private Sub cmdEntry_Click() Dim 行 As Long Dim 確認 As Integer 確認 = MsgBox("データを登録します。" _ & "よろしいですか?", vbYesNo) If 確認 <> vbYes Then Exit Sub 行 = [Database].Rows.Count + 1 [Database].Cells(行 - 1, 1).EntireRow.Insert [Database].Offset(行 - 1).Resize(1).Copy _ [Database].Cells(行 - 1, 1) [Database].Offset(行 - 1).Resize(1).ClearContents [Database].Cells(行, 1) = txtNo.Value [Database].Cells(行, 2) = txtName.Text If optMale.Value = True Then [Database].Cells(行, 3) = "男性" Else [Database].Cells(行, 3) = "女性" End If [Database].Cells(行, 4) = cboBlood.Text [Database].Cells(行, 5) = txtAge.Value If chkWin.Value = True Then _ [Database].Cells(行, 6) = "○" If chkMac.Value = True Then _ [Database].Cells(行, 7) = "○" If chkLinux.Value = True Then _ [Database].Cells(行, 8) = "○" If chkOther.Value = True Then _ [Database].Cells(行, 9) = "○" If chkOther.Value = True Then _ [Database].Cells(行, 10) = "○" Unload frmNew End Sub Private Sub cmdCancel_Click() Unload frmNew End Sub

  • Excel VBA BeforeDoubleclickについて

    VBA初心者です。 拙いスキルではどうにもならなくて困っております。 お分かりになられる方おられましたら ご教授ください。 _|___A___|___B___|___C___|_ 1| aaa | bbb | ccc 2| ddd | eee | fff 3| 4| --- | +++ | *** 5| ### | $$$ | &&& 6| %%% | ???? | \\\ 7| >>> | <<< | /// 8| 以上のような表がありまして、 セルをダブルクリックした場合、たとえば A4,A5をダブルクリックするたび⇒A1文字列にA4/A5文字列を追加 A6,A7をダブルクリックするたび⇒A2文字列にA6/A7文字列を追加 4~7行目以外をダブルクリック⇒何もしない という動作を各行ごとに実行(A列はA1/A2,B列はB1/B2へと追加) していくことができますでしょうか? サンプルコードなどご教授いただけますと幸いです。 何卒よろしくお願いいたします。