VBA 別ブックからの転記の高速化について
VBA 別ブックからの転記の高速化についてご教授下さい。
現在、下記のようなコードで作業してるのですが、マクロの実行をするととても時間がかかり困ってます。転記元のデータ数が、日々増えており日に日にかかる時間が増えてます。良い方法はご教授いただきたいです。よろしくお願いします。
Option Explicit
Const Scrbook As String = "●●●.xlsx"
Const Folder As String = "○○○"
Public Sub sheet1()
Dim dict As Object
Dim maxrow3 As Long
Dim row3 As Long
Dim key2 As Variant
Dim sh3 As Worksheet
Dim Vals As Variant
Dim sname As String
Dim row2 As Long
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Set dict = CreateObject("Scripting.Dictionary")
Workbooks.Open Filename:=Folder & "\" & Scrbook, ReadOnly:=True, UpdateLinks:=0
Call GetlDs("●●●", dict)
ThisWorkbook.Activate
Set sh3 = Worksheets("Sheet1")
maxrow3 = sh3.Cells((Rows.Count), "F").End(xlUp).row
For row3 = 4 To maxrow3
key2 = sh3.Cells(row3, "F").Value
If dict.exists(key2) = True And sh3.Cells(row3, "H") = "" Then
Vals = Split(dict(key2), "|")
sname = Vals(0)
row2 = Vals(1)
sh3.Cells(row3, "E").Value = Workbooks(Scrbook).Worksheets(sname).Cells(row2, "C").Value
sh3.Cells(row3, "G").Value = Workbooks(Scrbook).Worksheets(sname).Cells(row2, "Z").Value
sh3.Cells(row3, "H").Value = Workbooks(Scrbook).Worksheets(sname).Cells(row2, "H").Value
sh3.Cells(row3, "I").Value = Workbooks(Scrbook).Worksheets(sname).Cells(row2, "G").Value
sh3.Cells(row3, "J").Value = Workbooks(Scrbook).Worksheets(sname).Cells(row2, "L").Value
sh3.Cells(row3, "K").Value = Workbooks(Scrbook).Worksheets(sname).Cells(row2, "K").Value
sh3.Cells(row3, "M").Value = Workbooks(Scrbook).Worksheets(sname).Cells(row2, "DQ").Value
sh3.Cells(row3, "O").Value = Workbooks(Scrbook).Worksheets(sname).Cells(row2, "T").Value
sh3.Cells(row3, "P").Value = Workbooks(Scrbook).Worksheets(sname).Cells(row2, "V").Value
Else
'sh3.Cells(row, "E").Value = ""
'sh3.Cells(row, "G").Value = ""
'sh3.Cells(row, "H").Value = ""
'sh3.Cells(row, "I").Value = ""
'sh3.Cells(row, "J").Value = ""
'sh3.Cells(row, "K").Value = ""
'sh3.Cells(row, "M").Value = ""
'sh3.Cells(row, "O").Value = ""
'sh3.Cells(row, "P").Value = ""
End If
Next
Workbooks(Scrbook).Close
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Private Sub GetlDs(ByVal sname As String, ByVal dict As Object)
Dim maxrow As Long
Dim row As Long
Dim key As Variant
Dim sh3 As Worksheet
Set sh3 = Worksheets(sname)
maxrow = sh3.Cells((Rows.Count), "A").End(xlUp).row 'ID
For row = 2 To maxrow
key = sh3.Cells(row, "A")
dict(key) = sname & "|" & row
Next
End Sub
No.18ベストアンサー
- 回答日時:
>「dict(key) = row1 - 2 + 1」のところがわかりません、もしよかったら教えて頂けませんか?
転記元の転記対象の列を全て、配列に入れて処理しています。
例として、2000行まであった場合、C列については、C2:C2000までを配列Carrに入れています。
配列Carrの先頭は、Carr(1,1)になります。
つまり
2行目のC2の値->Carr(1,1)
3行目のC2の値->Carr(2,1)
4行目のC2の値->Carr(3,1)
のようになります。
2行目のIDに対応する値は1なので、row1 - 2 + 1=1となります。
3行目のIDに対応する値は2なので、row1 - 2 + 1=2となります。
もし、5行目から開始しているなら、5行目が先頭なので
For row1 = 5 To maxrow1
key = sh1.Cells(row1, "A")
dict(key) = row1 - 5 + 1
Next
になります。
>速くなりました!
どのくらい、速くなったのでしょうか。具体的な数値を教えていただけるとありがたいです。
又、実行後、イミデイトウィンドウに
メモリ転記
Open 0.999999999996959
GetIDs 0
Sheet1 0
のような数値が表示されますが、Open、GetIDs、Sheet1の値はいくつになってますでしょうか。
イミデイトウィンドウは、添付図のように
VBEの画面で、表示(V)->イミデイトウィンドウ(I)をクリックすると表示されます。
No.19
- 回答日時:
No17でアップしたソースに誤りがありましたのでお詫びして訂正します。
こちらに変えてください。失礼しました。
https://ideone.com/BFxAls
変更箇所は、
68,69行の
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
です。
Application.Calculation = xlCalculationAutomaticがないと
excelが手動計算のままになってしまいます。
修正個所、ありがとうございます!
イミデイトウィンドウのところですが、会社のPCなんできっちりとは覚えてないですが、
Open 0.8.........
GetIDs 0
Sheet1 0
くらいでした。
解説もしていただき、本当にありがとうございます!!
No.17
- 回答日時:
>データの内容は変更しませんが、データ自体が増える事はあるので、こちらの方法は難しそうです。
すみません、、、。そうでしたら、メモリ上で、処理を行うようにするのが、残されている方法です。これでだめならこれ以上の対策は難しいかと思います。
下記にアップしました。
転記元のブックは転記元.xlsx、転記元のシート名は転記元にしてあります。
https://ideone.com/RVd8zQ
上記を実行すると、イミデイトウィンドウに例として以下のように表示されます。
メモリ転記
Open 0.999999999996959
GetIDs 0
Sheet1 1.00000000000655
上記の値の合計が、処理時間になります。
ありがとうございます!速くなりました!!結局、コードをまるまる作って頂くかたちになってしまいすみません!今、コードをきちんと理解する為に解読していますが、39行目の「dict(key) = row1 - 2 + 1」のところがわかりません、もしよかったら教えて頂けませんか?
No.16
- 回答日時:
補足ありがとうございました。
>PCスペックですが、corei3の4Gでした。
全てメモリ上で行うようにして、効果があるかどうかは微妙です。
ちょっとメモリが足りないような気がしますが、効果があるかもしれません。
まずは、下記の追加した行のみ処理するように改造するのが、先決かと考えます。
>一度増えたデータは書き変えず、毎日追加されます。
本当に書き換えないなら、この方法が有効になります。
念のための確認ですが、以下のようなケースの場合、前日の処理をリカバリできませんがよろしいでしょうか。
①昨日、転記先に11行~15行までを追加し、処理をおこなった。
②但し、F列のIDが転記元に存在しないために、11行~15行の他の列(E列,G列,H列,I列...)にはなにも転記されなかった。
(F11,F12,F13,F14,F15のIDが転記元に存在しない)
③本日、転記先に、16行~18行まで追加された。
この時、F11,F12,F13,F14,F15のIDが転記元に存在するようになっていた。
既存の処理では、11行~15行について、転記元にIDが存在するので、11行~15行の他の列(E列,G列,H列,I列...)に転記が行われます。
改造後の処理では、16行~18行しか行わないので、11行~15行については、一切処理されません。
上記のようになりますが、よろしいでしょうか。
それで良い場合は、作業用に1列を使用しますので、空いている列を提示してください。(仮にDA列とします)
以下の手順で追加された列のみを処理するようにします。
1.マクロ実行時、作業が終了した行(F列の最後の行)のDA列に常に1を設定します。
2.前日に、11行から15行まで、処理すると、DA11~DA15まで1が設定されます。
3.当日、16行~18行まで追加された場合、DA15まで1が設定されているので、16行から開始を行い、18行まで処理する。
(処理が終わるとDA16~DA18に1が設定される)
4.以降同様に繰り返す。
上記でOKでしたら空いている列を提示してください。
色々考えてくださり、本当にありがとうございます!
提示してくださった確認内容ですが、昨日なかったデータが今日入っているということはあります。データの内容は変更しませんが、データ自体が増える事はあるので、こちらの方法は難しそうです。すみません、、、。
No.15
- 回答日時:
当方の環境で、どこで時間がかかっているかがわかるようにするために、
各処理毎の時間計測を行いました。
マクロは下記にアップしています。
https://ideone.com/zILYjq
転送元 20000行×160列
転送先 3000行×100列
のデータを処理した結果です。
イミデイトウィンドウに以下のように表示されます。
転記
Open 7.99999999999965
GetIDs 0
Sheet1 3.00000000000047
openは転記元の.xlsxのオープンに要した時間(単位:秒、以下同様)
GetIDsはdictの作成に要した時間
Sheet1はSheet1の設定に要した時間
ファイルのオープン時間で約8秒、Sheet1の作成で約3秒かかっていることがわかります。
あなたの環境でどこで時間がかかっているかチェックしてください。
---------------------------------------------------------
提示したマクロ中のファイルのパス名、シート名はこちらの環境に合わせてます。
Dim t0, t1, t2, t3
で、下記時間の定義をしています。
t0 = Time
t1 = Time
t2 = Time
t3 = Time
で各処理を行った時の時間を記憶します。
(これを埋め込む位置を間違わないようにしてください)
Debug.Print "転記"
Debug.Print "Open", 86400 * (t1 - t0)
Debug.Print "GetIDs", 86400 * (t2 - t1)
Debug.Print "Sheet1", 86400 * (t3 - t2)
で各処理の所要時間を表示します。
No.14
- 回答日時:
>転送元のデータは2000行×160列で、1日に50件ほど増えます。
>転送先のデータは200行×100列でこちらは1日に5件ほど増えます。
当方、10年ほど前のPCですが(Corei5 メモリ12G)
転送元 20000行×160列
転送先 3000行×100列
のデータを作成し、提示されたマクロを実行すると、11秒程度でした。
あなたの環境では、どの程度の時間を使ってますか。
何秒以内が目標値なのでしょうか。また、あなたのPCのスペック(メモリサイズとCPU)は、どの程度でしょうか。
対策案としては、
①全てメモリに格納して行うようにする。(十分な実装メモリが必要)
②転送先の処理をデータが増えた行のみに限定してよいなら(毎日の増加分の5件)、そのような仕組みを作る。
(但し、今までのデータでもF列及びH列の内容が変わることがあるなら、その分の書き換える必要があるので、この方法は採用不可)
が考えられます。
デモを作って試してくださり、本当にありがとうございます!!!pcは会社のなので詳しくは分かりません。実行してかかる時間は長いとおそらく2.3分かかっていると思います。
転送先のデータの増える数は平均して50件程です。一度増えたデータは書き変えず、毎日追加されます。
No.12
- 回答日時:
>しかし、別ブックからの転記がどのようになってるのかわかりません。
#7のコードで sBk.Close 'ここで閉じる までが別ブックの処理です
別ブックを開いてsBk.Worksheets("●●●")シートのA2セルから最終A列セルまでの値を初めに配列arrに入れます
その配列要素をDictionaryのキーとして登録し同時にarr要素と同じ行の値を
Itemに区切り文字を加えて登録しています
元のコード
key = sh3.Cells(row, "A")
dict(key) = sname & "|" & row
A列の値は一意のIDのような存在だと思いますので 必要なデータをすべて連想配列に登録しています
登録を終了すれば"●●●.xlsx"は不要と思われますので 閉じています
後は#11のコードでデータを照合して Dictionaryにあれば
そのItemを分離してすべての処理が終わるまで格納用配列に代入して
抽出処理が終わったら、該当列に出力する流れです
処理を行わない行が含まれている場合、空白になって今うため
格納用配列をあらかじめ現状データで作る方法を取っていますが
この処理と1行ずつ処理する方法の処理時間の差はデータ無いようにもよりますしデモデータを作成していませんので分かりません。。
No.11
- 回答日時:
めぐみん_さん そうですよね
#6自分でも書いていたに処理に入れていませんでした 中途半端なのと
変数も使い廻しでしたので辞書を使う側を変更してみました。。
'データ加工(分岐処理)
Dim eArr As Variant, gArr As Variant
Dim mArr As Variant, oArr As Variant
Dim c As Range
Dim first_row As Long, end_row As Long
With writing_sheet
first_row = Range("H4").End(xlDown).Row + 1
end_row = .Cells((Rows.Count), "F").End(xlUp).Row
eArr = .Range(.Cells(first_row, "E"), .Cells(end_row, "E")).Value
gArr = .Range(.Cells(first_row, "G"), .Cells(end_row, "K")).Value
mArr = .Range(.Cells(first_row, "M"), .Cells(end_row, "M")).Value
oArr = .Range(.Cells(first_row, "O"), .Cells(end_row, "P")).Value
n = 1
For Each c In .Range(.Cells(first_row, "F"), .Cells(end_row, "F"))
key2 = c.Value
'登録が無く、H列セルに値があれば処理しない
If dict.exists(key2) = True And c.Offset(, 2) = "" Then
Vals = Split(dict(key2), "|")
eArr(n, 1) = Vals(0)
gArr(n, 1) = Vals(1)
gArr(n, 2) = Vals(2)
gArr(n, 3) = Vals(3)
gArr(n, 4) = Vals(4)
gArr(n, 5) = Vals(5)
mArr(n, 1) = Vals(6)
oArr(n, 1) = Vals(7)
oArr(n, 2) = Vals(8)
n = n + 1
Else
n = n + 1
End If
Next
'データ 出力
Application.ScreenUpdating = False
.Cells(first_row, "E").Resize(UBound(eArr)).Value = eArr
.Cells(first_row, "G").Resize(UBound(gArr), UBound(gArr, 2)).Value = gArr
.Cells(first_row, "M").Resize(UBound(mArr)).Value = mArr
.Cells(first_row, "O").Resize(UBound(oArr), UBound(oArr, 2)).Value = oArr
End With
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
細かく、ありがとございます!
なんとなく教えていただいたコードは理解できたように思います。
しかし、別ブックからの転記がどのようになってるのかわかりません。dictionayは使わない方法ですか?ちょっと混乱中です、、、。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) VBAコードが作動せず、どこに問題があるのか教えて下さい。 3 2023/06/13 13:20
- Excel(エクセル) VBAの指示の内容 昨日こちらでご教示頂いたのですが初心者な為、一つ一つの指示が何をやっているのかわ 2 2022/10/25 18:08
- Visual Basic(VBA) VBA処理追加 こちらでご教示頂いたのですが回答完了させてしまいましたのでこちらからまた質問させてく 2 2022/10/27 09:57
- Visual Basic(VBA) vbaを早くしたい 5 2022/09/09 10:58
- Visual Basic(VBA) VBA初心者です。 2 2022/10/10 11:52
- Excel(エクセル) なぜExit Subがあるのかわかりません 4 2023/02/19 12:34
- Visual Basic(VBA) 【VBA】特定のワードが入っている行全体を塗りつぶしたい 4 2022/04/20 15:22
- Visual Basic(VBA) マクロで最終行を取得したい 4 2023/05/28 12:14
- Visual Basic(VBA) VBAで質問ですが、皆さんはどの様に導き出しているのでしょうか? 6 2022/05/03 21:53
- Visual Basic(VBA) いつもお世話になっております、VBAで教えて頂きたいのですが 2 2022/05/05 22:20
このQ&Aを見た人はこんなQ&Aも見ています
-
見学に行くとしたら【天国】と【地獄】どっち?
みなさんは、一度だけ見学に行けるとしたら【天国】と【地獄】どちらに行きたいですか? 理由も聞きたいです。
-
スマホに会話を聞かれているな!?と思ったことありますか?
スマートフォンで検索はしてないのに、友達と話していた製品の広告が直後に出てきたりすることってありませんか? こんな感じでスマホに会話を聞かれているかも!?と思ったエピソードってありますか?
-
【大喜利】【投稿~12/17】 ありそうだけど絶対に無いことわざ
【お題】 ・ありそうだけど、絶対に無いことわざを教えてください。
-
【選手権お題その1】これってもしかして自分だけかもしれないな…と思うあるあるを教えてください
「出身中学と出身高校が混ざったような校舎にいる夢を見る」「まぶたがピクピクしてるので鏡で確認しようとしたらピクピクが止まってしまう」など、 これってもしかして自分だけかもしれないな…と思うあるあるを教えてください
-
冬の健康法を教えて!
温度変化が大きくなり、風邪をひきやすいこれからの季節。 どんなことに気をつけていますか?
-
VBA 別ブックからコピペしたいのですが、軽くしたいです
Visual Basic(VBA)
-
VBAでブックを非表示で開いて処理して閉じる方法
Excel(エクセル)
-
VBAで複数のブックを開かずに処理する方法
Visual Basic(VBA)
-
-
4
VBAで保存しないで閉じると空のBookが残る
Excel(エクセル)
-
5
【マクロ】【VBA】別ブックへのデータ転記について
Excel(エクセル)
-
6
VBA バックグラウンドで別ブックを開いてデータ転記
Excel(エクセル)
-
7
WorkBooksをオープンさせずにシートにコピーしたい【EXCEL VBA】
Excel(エクセル)
-
8
別ファイルを開かず、INDIRECT関数を使用せずに、別ファイルのデータを求めたい
Excel(エクセル)
-
9
VBA 別ブックから条件に合うものを転記したいです
Visual Basic(VBA)
-
10
エクセルVBAで5行目からオートフィルタモードに設定したいたい
Excel(エクセル)
-
11
エクセルVBAでセルに入力したパスでブックを開く
Excel(エクセル)
-
12
エクセル VBA シートのコピー
その他(プログラミング・Web制作)
-
13
UserForm1.Showでエラーになります。
工学
-
14
数式による空白を無視して最終行を取得するマクロ
Excel(エクセル)
-
15
バックグラウンドのプロセスのエクセルを閉じる方法
Visual Basic(VBA)
-
16
【Excel VBA】指定行以降をクリアするには?
Visual Basic(VBA)
-
17
Excel 別ブックから該当データを検索、必要データを元ブックへ転記する方法について
Visual Basic(VBA)
-
18
【ExcelVBA】各セルをダブルクォーテーションで括ってCSV保存したい
Visual Basic(VBA)
-
19
VBAでの Replace関数で、ワイルドカードは使えないのでしょうか?
Visual Basic(VBA)
-
20
エクセルVBA コードが同じでもファイルによって処理速度が大きく変わるのはなぜ
Visual Basic(VBA)
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・「みんな教えて! 選手権!!」開催のお知らせ
- ・漫画をレンタルでお得に読める!
- ・【選手権お題その2】この漫画の2コマ目を考えてください
- ・2024年に成し遂げたこと
- ・3分あったら何をしますか?
- ・何歳が一番楽しかった?
- ・治せない「クセ」を教えてください
- ・【大喜利】看板の文字を埋めてください
- ・【大喜利】【投稿~12/17】 ありそうだけど絶対に無いことわざ
- ・【選手権お題その1】これってもしかして自分だけかもしれないな…と思うあるあるを教えてください
- ・【穴埋めお題】恐竜の新説
- ・我がまちの「給食」自慢を聞かせてっ!
- ・冬の健康法を教えて!
- ・一番好きな「クリスマスソング」は?
- ・集合写真、どこに映る?
- ・自分の通っていた小学校のあるある
- ・フォントについて教えてください!
- ・これが怖いの自分だけ?というものありますか?
- ・スマホに会話を聞かれているな!?と思ったことありますか?
- ・それもChatGPT!?と驚いた使用方法を教えてください
- ・見学に行くとしたら【天国】と【地獄】どっち?
- ・これまでで一番「情けなかったとき」はいつですか?
- ・この人頭いいなと思ったエピソード
- ・あなたの「必」の書き順を教えてください
- ・10代と話して驚いたこと
- ・14歳の自分に衝撃の事実を告げてください
- ・人生最悪の忘れ物
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
マクロの「SaveAs」でエラーが...
-
マクロ実行後に別シートの残像...
-
EXCELのSheet番号って変更でき...
-
VBA 別ブックからの転記の高速...
-
Changeイベントで複数セルへの...
-
楽天RSSからエクセルVBAを使用...
-
【VBA】特定の条件でセルをコピー
-
VBA 空白行に転記する
-
複数シートの複数列に入力され...
-
RemoveDuplicatesメソッドにつ...
-
Excelマクロで不要な行を繰り返...
-
ExcelのVBマクロを、バックグラ...
-
VBAで変数の数/変数名を動的に...
-
Excel VBA オートフィルターで...
-
Count Ifのセルの範囲指定に変...
-
VBA Userformで一部別シートに...
-
【VBA】データを各シートに自動...
-
エクセルVBAで他のbookのセ...
-
別シートから年齢別の件数をカ...
-
VBAを使って複数のシートから抽...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
マクロの「SaveAs」でエラーが...
-
マクロ実行後に別シートの残像...
-
EXCELのSheet番号って変更でき...
-
VBA 空白行に転記する
-
Count Ifのセルの範囲指定に変...
-
Changeイベントで複数セルへの...
-
VBAで変数の数/変数名を動的に...
-
VBA別シートの最終行の次行へ転...
-
楽天RSSからエクセルVBAを使用...
-
Excel2013で切り取り禁止
-
【VBA】特定の条件でセルをコピー
-
Unionでの他のシートの参照につ...
-
VBA 実行時エラー1004 rangeメ...
-
ExcelのVBマクロを、バックグラ...
-
100万件越えCSVから条件を満た...
-
複数シートの複数列に入力され...
-
VBA 別ブックからの転記の高速...
-
VBA Userformで一部別シートに...
-
テキストボックスから、複数の...
-
Excel VBA オートフィルターで...
おすすめ情報
皆さま、早速のご回答ありがとうございます。
ご指摘にありましたシート名ですが、転記元シートから転記先シートに移す感じです。画像は、スマホからなので貼り付け出来ませんが、、、すみません。
転記先シートのF列に番号を入力→マクロ実行→転記元シートから同じ番号の各情報を転記といった動きです。転記元シートと転記先シートは別のExcelブックに、なります。
前までは関数でしていたのですが、こちらも時間がかかるのと、関数を入れているセルに上書き等多発して、VBAで、と言うことになりました。また、転記元シートの並びは固定で変えられません。
tatsumaru77さんの質問にありましたPCスペックですが、corei3の4Gでした。
補足で、皆様へのお礼となってしまい、すみません!
皆さんが、教えてくださった事はどれも本当に勉強になりました!ベスとアンサーを決めるのが心苦しいくらい、、、、。
見捨てずに教えて下さり、本当にありがとうございました!!!