質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

1回答

2512閲覧

VBA 数万行 抽出 高速化

hajihaji

総合スコア18

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

1クリップ

投稿2020/03/25 06:25

編集2020/03/25 23:54

それぞれ数万行ある2シート間でデータの突合せをしようと思うのですが、どうしても動作中に固まってしまいます。
もっと早く動くようなやり方がありましたらご教示いただけましたら幸いです。

Dim sh1 As Worksheet Dim sh2 As Worksheet Dim Start As Date Dim Finish As Date Dim lrow As Long Dim i As Long Dim n As Long Dim R1 As Long Dim R2 As Long Dim key, key2 As Variant On Error Resume Next Set sh1 = Worksheets("Sheet1") Set sh2 = Worksheets("Sheet2") R1 = sh1.Cells(sh1.Rows.Count, "A").End(xlUp).row R2 = sh2.Cells(sh2.Rows.Count, "A").End(xlUp).row Application.ScreenUpdating = False Application.EnableEvents = False Application.DisplayAlerts = False Application.Calculation = xlCalculationManua '計算を手動 For lrow = 2 To R1 For i = 2 To R2 key = sh1.Cells(lrow, "A").Value & "|" & sh1.Cells(lrow, "L").Value key2 = sh2.Cells(i, "A").Value & "|" & sh2.Cells(i, "F").Value If sh1.Cells(lrow, "AR").Value = "" And key = key2 Then sh1.Cells(lrow, "AR") = sh2.Cells(i, "AB") End If Next i Next lrow Application.StatusBar = False Application.Calculation = xlCalculationAutomatic Application.DisplayAlerts = True Application.EnableEvents = True Application.ScreenUpdating = True Finish = Time MsgBox "取得が完了しました" & vbLf & "実行"

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yureighost

2020/03/25 08:37

コードが正しく張り付けられてないため読み辛いですが、 ぱっと見た感じでもForを二重にして処理しているようなので、 If sh1.Cells(lrow, "AR").Value = "" And key = key2 Then sh1.Cells(lrow, "AR") = sh2.Cells(i, "AB") End If の部分で一致するものが一つだとわかっているなら、 sh1.Cells(lrow, "AR") = sh2.Cells(i, "AB") の下に Exit For と入れて内側のFor文を即座に抜けさせることで大分処理を軽くできます。 ただ二つ以上一致する物があると想定されていると使えませんが。
meg_

2020/03/25 10:45

・コードは「コードの挿入」で記入してください。 ・「どうしても動作中に固まって」というのはVBAの実行が止まるという意味でしょうか?
hajihaji

2020/03/25 23:56

失礼しました。コードを入れなおしました。 ありがとうございます試してみます。 実行が止まるというのはかなり遅くエラーになるという意味です。 ありがとうございます。
meg_

2020/03/26 00:27

エラーが出ているのであれば、そのエラーを掲載してください。遅いのとエラーが発生するのとでは大分違います。※ところでメモリは足りていますか?
hajihaji

2020/03/26 00:33

応答していないというエラーです。デバックとかではありません。
meg_

2020/03/26 02:07

ああ、エラーではなく、エクセルが固まったということですね。待てば処理が終わるということですね。 エクセルでデータ数が多いとある程度時間が掛かるのは仕方ないかもしれません。
guest

回答1

0

ベストアンサー

If sh1.Cells(lrow, "AR").Value = "" And key = key2 Then

sh1のAR列の値が空白でないなら突合せのためのkeyをつくる必要がないので
先にAR列値の判定をしたほうが良いと思います
また効率重視するなら参照先データを配列dictionaryに格納した方が良いと思います

VBA

1Sub test() 2  Dim rng1 As Range 3  Dim rng2 As Range 4  Dim R1  As Long 5  Dim R2  As Long 6  Dim i  As Long 7  Dim key As String 8  Dim dic As Object '"scripting.dictionary" 9  Dim ret 10 11  'https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/dictionary-object 12  Set dic = CreateObject("scripting.dictionary") 13 14  '参照先Sheet2のA1:AB?範囲のうち、keyと値を配列dicに入れる 15  With Worksheets("Sheet2") 16    R2 = .Cells(.Rows.Count, "A").End(xlUp).Row 17    Set rng2 = .Range("A1:AB1").Resize(R2) 18    'keyが重複していたら前方優先するため逆順Loopする(後方優先なら正順) 19    For i = R2 To 2 Step -1 20      '1=A 6=F 28=AB 21      dic(CStr(rng2(i, 1).Value & "|" & rng2(i, 6).Value)) = rng2(i, 28).Value 22    Next 23  End With 24 25  With Worksheets("Sheet1") 26    R1 = .Cells(.Rows.Count, "A").End(xlUp).Row 27    '検索keyをつくる範囲絞込み 28    Set rng1 = .Range("A1:L1").Resize(R1) 29    '結果書き出し用 30    ret = .Range("AR1").Resize(R1).Value 31    For i = 2 To R1 32      If ret(i, 1) = "" Then 33        '検索key 1=A 12=L 34        key = CStr(rng1(i, 1).Value & "|" & rng1(i, 12).Value) 35        '配列dicにあれば、登録したItem(値)を持ってくる 36        If dic.exists(key) Then 37          ret(i, 1) = dic.Item(key) 38        Else 39          ret(i, 1) = "N/A" 40        End If 41      End If 42    Next 43    '.Range("AR1").Resize(R1).Value = ret 44    '↓とりあえず別の列に結果書き出し。"BA1"は適宜変更してください 45    .Range("BA1").Resize(R1).Value = ret 46  End With 47End Sub 48

投稿2020/03/25 09:09

end-u

総合スコア52

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hajihaji

2020/03/26 00:04

ご回答ありがとうございます。 さっそく実行させていただきましたところ。 '結果書き出し用 ret = .Range("AR1").Resize(R1).Value  の箇所でデバックとなりWithブロック変数が設定されておりませんと出てしまいます。  retの宣言がないとか関係があるのでしょうか。 おそれいりますがご教示いただければ幸いにございます。
end-u

2020/03/26 02:08

いや宣言はしてますけどね? > Dim ret Dim ret As Variant としてねんのため型指定してみてください それでもダメな時は変数名を変更 Dim vntAR As Variant とでもしてモジュール内変数retを全て置換してください
hajihaji

2020/03/26 02:23

Variantとしましたら動きました。 恐ろしく早くなりました。 本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問