シート1には13,000行、
シート区分マスターには25,000行において
シート1の検索値からシート区分マスターを検索して
ヒットしたらシート1に返したいです。
シート1のデータ行文行いたいです。
シート1の行数は常に変化、
シート区分マスターの行数は固定です。
以下の記述で検索を行いますが終了するのに
5分強かかります。
(下のほうに再計算0%→5%→70%→95%と表示されている)
もっと早く処理させる方法はありますでしょうか?
よろしくお願いします。
Sub 区分検索()
'2010 年11月18日
'シート1のA列を検索値として
'シート区分マスターのA列を検索しヒットしたら
'シート区分マスターの該当行のE列をシート1のC列に転記
'データはそれぞれのシートともに2列目からである
'ヒットしない場合はシート1のC列は空白にする
'検索値と転記するセルのシート選択
With Sheets("シート1")
'データ開始行のC2に式を入れる
.Range("C2").Formula = _
"=IF(ISNA(VLOOKUP(A2,区分マスター!$A:$E,5,FALSE)),"""",VLOOKUP(A2,区分マスター!$A:$E,5,FALSE))" '数式入力
'式によって抽出されてC列に転記された値をコピーします。
.Range("C2").Copy .Range("C2:C" & .Range("A" & .Rows.Count).End(xlUp).Row) 'データ最終行までコピー
.Columns("C:C").Copy
'コピーした値をC1から値貼付を行う
.Range("C1").PasteSpecial Paste:=xlPasteValues 'C列を値に変換
Application.CutCopyMode = False
End With
End Sub
No.7ベストアンサー
- 回答日時:
元々、Sub dictest2()は、
VLOOKUPと同じ答えを出すと同時に、
"区分マスター"に重複がある、
という事をチェックしてもらう為に書いたものです。
例えば
A列 B列
key item
a 1
b 2
c 3
a 4
このような『マスタ』で"a"をVLOOKUP検索すると
=VLOOKUP("a",A:B,2,0)
=1
となります。
先に見つかった"a"のitem 1 が答えです。
Sub dictest()では
>For i = 1 To UBound(v)
> dic(v(i, 1)) = i
>Next
この箇所で、dictionaryオブジェクトにkeyを登録してます。
上の例でいけば
"a","b","c","a"..です。
"a"が重複していた場合は後の"a"で【上書き】されます。
この時登録されるitemは 4 です。
だから、このような登録の仕方をすると
取り出されるkeyは、【後】から登録した"a"で、itemは 4 になります。
対して、Sub dictest2()では
>For i = 1 To UBound(v)
> '修正箇所
> If dic.exists(v(i, 1)) Then
> Debug.Print "重複", v(i, 1)
> Else
> dic(v(i, 1)) = w(i, 1)
> End If
>Next
この箇所で、dictionaryオブジェクトにkeyを登録してます。
If dic.exists(v(i, 1)) Then ...existsメソッドを使って、
keyが【既に】登録されていれば、
登録せずに[イミディエイトウィンドウ]に"重複"..と書き出します。
keyが未登録だったら登録します。
Sub dictest2()では
取り出されるkeyは、【前】に登録した"a"で、itemは 1 になります。
VLOOKUPと同じ動きをするのはSub dictest2()です。
『マスタ』に重複がなく、ユニークなkeyであれば
Sub dictest()もSub dictest2()も同じ結果になります。
速度的に有利なのはSub dictest()だと思います。
dictionaryオブジェクトを使ってデータ検索をする場合、
検索データが重複していた場合に、前優先か後優先かで
コードの書き方が変わります。
検索と同時に重複をチェックしたいなら、
Sub dictest2()のようにexistsメソッドを使います。
あるいはSub dictest()でkeyを登録する時に、逆にLoopすれば
:
For i = UBound(v) To 1 Step -1
dic(v(i, 1)) = i
Next
:
前優先になります。
結論として、
『マスタ』の重複はあり得ないのが基本だと思いますから、
Sub dictest()で良いはずです。
勉強してくださいね。とURLまで貼ってくれたのですが、
それを見てもいまいち理解できませんでした。
今回の回答で、やっと理解しました。
すごく分かりやすい説明で、嬉しかったです。
おかげでマスターがでたらめだった事がわかり大変感謝です。
セルにVLOOKUP式を入れて運用していたのですが
気がつきませんでした。
マクロでもVLOOKUP式を貼り付けるつもりでいたので
セルに式を入れたのと同じ結果のはずで
マスターの不備は気がつかなかったと思います。
高速化でアドバイスいただいた結果マスター不備にたどり着き
大変感謝です。
どうもありがとうございました。
No.6
- 回答日時:
>VLOOKUPで行った時と
>この記述で行った時で
>返ってきた値が相違する行が2,000行ほどあります。
ありゃ。
そうですか。
Sub dictest2()
Dim dic As Object
Dim i As Long
Dim v, w
Dim t As Single
t = Timer
With Sheets("区分マスター")
With .Range("E2", .Cells(.Rows.Count, 1).End(xlUp))
v = .Columns(1).Value
w = .Columns(5).Value
End With
End With
Set dic = CreateObject("scripting.dictionary")
For i = 1 To UBound(v)
'修正箇所
If dic.exists(v(i, 1)) Then
Debug.Print "重複", v(i, 1)
Else
dic(v(i, 1)) = w(i, 1)
End If
Next
With Sheets("シート1")
With .Range("A2", .Cells(.Rows.Count, 1).End(xlUp))
v = .Value
For i = 1 To UBound(v)
If dic.exists(v(i, 1)) Then
v(i, 1) = dic(v(i, 1))
Else
v(i, 1) = "無"
End If
Next
With .Offset(, 2)
.ClearContents
.Value = v
End With
End With
End With
Set dic = Nothing
Debug.Print Timer - t
End Sub
これでチェックしてください。
実行後、VBE画面[ctrl]+[g]キー。[イミディエイトウィンドウ]に
"重複" キーが書き出されてたら、Sheets("区分マスター")が重複してます。
"マスター"なのでキー重複はないと判断しましたが、
あれば、それも問題ですね。
どうもありがとうございました。
Sub dictest( )
→VLOOKUPで行った時と返ってきた値が相違する行が
シート1の13,000行中、約2,000行ありました。
↓↓↓
Sub dictest2( )
→VLOOKUPで行った時と同一になりました。
>実行後、VBE画面[ctrl]+[g]キー。
>[イミディエイトウィンドウ]に
>"重複" キーが書き出されてたら、
>Sheets("区分マスター")が重複してます。
すでに解決(VLOOOKUPの時と同じになった)しましたが
念の為、上記内容を確認しました。
重複キーが出てきました。
「区分マスター」を調査したら
25,000行中A列の値の重複が約11,000行もありました。
「区分マスター」を整理整頓し、A列の値の重複は無しにしました。
結果 「区分マスター」は 25,000行 → 約14,000行 になりました。
この「区分マスター」修正後に
Sub dictest2( )をもう一度行ってみました。
→VLOOKUPで行った時と同一になりました。
→「区分マスター」修正前にSub dictest2( )で行った時と同じでした。
あれっ?と思い「区分マスター」修正後に
もう一度 Sub dictest( ) を試してみました。
→VLOOKUPで行った時と同一になりました。
原因は
「区分マスターに重複行があった為」みたいです。
・Sub dictest2( )を作成していただかなくても大丈夫だった
になってしまいました。
大変申し訳ありませんでした。
教えていただいた
・Sub dictest( )と
・Sub dictest2( )なのですが
Sub dictest2( )は「区分マスター」に重複があっても
VLOOKUPと同じになるので
Sub dictest2( )を使用した方が安全でしょうか?
それとも「区分マスター」に重複があると
Sub dictest( )と
Sub dictest2( )のどちらでも、相違する値が出る可能性があるのでしょうか?
(区分マスターが重複していればVLOOKUPで行った時の
返した値も信憑性がありません。
重複していても返す値のあるE列の値が同じならいいのですが相違すれば
どちらの値が返されるか分かりません。)
金曜日から混乱しています。お礼が遅れてしまいました。
申し訳ありません。
No.5
- 回答日時:
おはようございます、gx9wxさん。
一夜明けたら、わたしが常に尊敬するend-uさまから、驚異的なコードが提案されていますね!
VLOOKUP検索のかわりにDictionaryオブジェクトを使うなんて、これまで考えたこともなかった・・・。
2万行でためしたらわずか0.625秒!
比較にもなりません。
end-uさま、脱帽です。(o。_。)oペコッ
よい勉強をさせていただきました。
merlionXXさん。おはようございます。
merlionXXもありがとうございます。
いろいろ教えていただきました。
merlionXXに教えていただいた今までの物も
(このスレッド以外も含め)
私にとっては驚異的です。
さてend-uさんに教えていただいたこの記述ですが、
テストも終了しこれを使いたいと思います。
で例によって1行ごとに何をしているのか、これからコメントを入れていくのですが
完全にちんぷんかんぷんです。
URLも貼り付けてくれたのでにらめっこです。
No.4
- 回答日時:
>dictionaryオブジェクトを使ったりする事になります。
一応、サンプル書いておきますね。
Sub dictest()
Dim dic As Object
Dim i As Long
Dim v, w
Dim t As Single
t = Timer
With Sheets("区分マスター")
With .Range("E2", .Cells(.Rows.Count, 1).End(xlUp))
v = .Columns(1).Value
w = .Columns(5).Value
End With
End With
Set dic = CreateObject("scripting.dictionary")
For i = 1 To UBound(v)
dic(v(i, 1)) = i
Next
With Sheets("シート1")
With .Range("A2", .Cells(.Rows.Count, 1).End(xlUp))
v = .Value
For i = 1 To UBound(v)
If dic.exists(v(i, 1)) Then
v(i, 1) = w(dic(v(i, 1)), 1)
Else
v(i, 1) = "無"
End If
Next
With .Offset(, 2)
.ClearContents
.Value = v
End With
End With
End With
Set dic = Nothing
Debug.Print Timer - t
End Sub
『vba scripting.dictionary』でnet検索して勉強してみてください。
http://www.eurus.dti.ne.jp/~yoneyama/Excel/vba/v …
この回答への補足
申し訳ありません。
VLOOKUPで行った時と
この記述で行った時で
返ってきた値が相違する行が2,000行ほどあります。
原因が分かりません。
多分と思われるのが
シート1の検索値(シート1のA列)に重複レコードがうじゃうじゃランダムに存在するという事くらいですが
重複していない1行のみしかいない行であっても
返ってきた値が相違しています。
信じられません。
26,000行で1秒かかりませんでした。
会社にあるエクセルシートでマクロではなくセルに直接vlookupの式を入れてある物
に流用したいと思います。
(ほとんどが15,000行を25,000行の中から検索で
再計算とかで処理が重くて困っていました。)
どうもありがとうございました。
No.3
- 回答日時:
VLookup自体が重いので、劇的に改善しようと思えば
dictionaryオブジェクトを使ったりする事になります。
Sub 区分検索02()を少しでも改善するなら
Sub test1()
Dim r As Range
Dim ri As Range
Dim t As Single
t = Timer
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
With Sheets("シート1")
Set r = .Range("A2", .Cells(.Rows.Count, 1).End(xlUp)).Offset(, 2)
End With
r.ClearContents
On Error Resume Next
For Each ri In r
ri.Value = WorksheetFunction.VLookup(ri.Offset(, -2), Worksheets("区分マスター").Range("A1:E60000"), 5, 0)
Next
On Error GoTo 0
r.Replace "", "無", xlWhole
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Debug.Print Timer - t
End Sub
また、ApplicationレベルでVLookupを使って配列に対して処理をすると
環境によっては速く処理できます。
#Excel2000では配列制限があるためこのままでは使えないです。
Sub test2()
Dim v
Dim t As Single
t = Timer
With Sheets("シート1")
With .Range("A2", .Cells(.Rows.Count, 1).End(xlUp))
v = Application.VLookup(.Value, Worksheets("区分マスター").Range("A1:E60000").Value, 5, 0)
With .Offset(, 2)
.ClearContents
.Value = v
.Replace "#N/A", "無", xlWhole
End With
End With
End With
Debug.Print Timer - t
End Sub
この回答への補足
2010年11月19日 12:00
申し訳ありません。
回答A-NO.4の補足で間違いです。
>VLOOKUPで行った時と
>この記述で行った時で
>返ってきた値が相違する行が2,000行ほどあります。
>原因が分かりません。
>多分と思われるのが
>シート1の検索値(シート1のA列)に重複レコードがうじゃうじゃランダムに存在するという事くらいですが
>重複していない1行のみしかいない行であっても
>返ってきた値が相違しています。
>投稿日時 - 2010-11-19 11:51:18
重複レコードはありませんでした。
ですが
VLOOKUPで行った時と
この記述で行った時で
返ってきた値が相違する行が2,000行ほどあります。
申し訳ありません。
ありがとうございます。
かなり早くなりました。
行数を倍にしても大丈夫です。
1.ここで教えていただいた表示と式停止の場合
13,500行=1:49
27,000行=3:35
2.質問後自作のLOOP文(記述は最後尾に)
13,500行=1:00
27,000行=1:58
3.今回教えていただいたSub test1()
13,500行=0:58
27,000行=1:54
4.今回教えていただいたSub test2()
13,500行=0:49
27,000行=1:36
質問では式を貼付して出た値を値貼付していた
↓
質問後自分で考えたloop文
Sub 区分検索02()
'2010 年11月18日
'シート1のA列を検索値として
'シート区分マスターのA列を検索しヒットしたら
'シート区分マスターの該当行のE列をシート1のC列に転記
'データはそれぞれのシートともに2列目からである
'ヒットしない場合はシート1のC列は空白にする
'検索値があるシート選択する
Sheets("シート1").Select
'そのシートの検索開始の行数を選択。2行目から開始。
Line = 2
'そのシートの検索値の列を指定1=A列。
'その値がなくなったら検索を終了させる。
Do Until Cells(Line, 1).Value = ""
'エラーとなっても次に進む
On Error Resume Next
'検索結果を転記する列を指定。Line3=C列
'検索するシートと列(1=A列)とヒットした場合のその行の返す値の列(5=E列)指定
Cells(Line, 3).Value = Application.WorksheetFunction.VLookup(Cells(Line, 1).Value, Worksheets("区分マスター").Range("A1:E60000"), 5, 0)
'VLOOKUP関数が終了又はエラーが発生したら止まる
On Error GoTo 0
'検索されなかったときの処理。
If Cells(Line, 3).Value = "" Then
Cells(Line, 3).Value = "無"
End If
'2行目から開始なので次の行の値を検索値とする
Line = Line + 1
'検索する値がなくなるまで繰返す
Loop
End Sub
No.2
- 回答日時:
画面停止だけじゃなく、計算停止も
Sub 区分検索02()
With Sheets("シート1")
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
.Range("C2").Formula = _
"=IF(ISNA(VLOOKUP(A2,区分マスター!$A:$E,5,FALSE)),"""",VLOOKUP(A2,区分マスター!$A:$E,5,FALSE))"
.Range("C2").Copy .Range("C2:C" & .Range("A" & .Rows.Count).End(xlUp).Row)
Application.Calculation = xlCalculationAutomatic
.Columns("C:C").Copy
.Range("C1").PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
Application.ScreenUpdating = True
End With
End Sub
5分が2分になりました。
ありがとうございます。
質問しておいてなんですが、
行数からしてLOOP文では絶対無理だと思いましたが
以下の記述だと1分で完了しました。
式を貼り付けて計算させて、でた値を値貼付するより
1行ごと処理する方が早いのでしょうか??
それとも13,000行位だと、1行ごと処理の方が早く
行数がもっと増えるとこれでは遅くなるのでしょうか?
早く処理できたにはいいのですが記述に問題があるのか
確信がもてず不安です。
Sub 区分検索02()
'2010 年11月18日
'シート1のA列を検索値として
'シート区分マスターのA列を検索しヒットしたら
'シート区分マスターの該当行のE列をシート1のC列に転記
'データはそれぞれのシートともに2列目からである
'ヒットしない場合はシート1のC列は空白にする
'検索値があるシート選択する
Sheets("シート1").Select
'そのシートの検索開始の行数を選択。2行目から開始。
Line = 2
'そのシートの検索値の列を指定1=A列。
'その値がなくなったら検索を終了させる。
Do Until Cells(Line, 1).Value = ""
'エラーとなっても次に進む
On Error Resume Next
'検索結果を転記する列を指定。Line3=C列
'検索するシートと列(1=A列)とヒットした場合のその行の返す値の列(5=E列)指定
Cells(Line, 3).Value = Application.WorksheetFunction.VLookup(Cells(Line, 1).Value, Worksheets("区分マスター").Range("A1:E60000"), 5, 0)
'VLOOKUP関数が終了又はエラーが発生したら止まる
On Error GoTo 0
'検索されなかったときの処理。
If Cells(Line, 3).Value = "" Then
Cells(Line, 3).Value = "無"
End If
'2行目から開始なので次の行の値を検索値とする
Line = Line + 1
'検索する値がなくなるまで繰返す
Loop
End Sub
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) まとめシートから集計シートへA列のコードが一致したら1行コピーするマクロをネット上で見つけました。こ 1 2022/08/30 14:11
- Visual Basic(VBA) 集計シートA列のコードと一致する右に並んだシート名(コード)の3行目から10行目をコピーして貼り付け 4 2022/08/18 15:24
- Excel(エクセル) VBAのoffsetの動き方について教えてください 3 2022/11/25 23:36
- Excel(エクセル) エクセルのマクロでコピー後の貼り付け先を毎回指定したところにしたい 5 2022/08/12 10:47
- Visual Basic(VBA) 【ご教示ください】VBAの記述方法がわかりません。 2 2022/08/12 21:28
- Excel(エクセル) VLOOKUP が機能しない、その原因は何 ? 8 2022/10/19 12:06
- Visual Basic(VBA) エクセル VBA 処理スピードを上げたいのですが。 6 2023/03/31 20:52
- Visual Basic(VBA) コード名シートA列と集計シートA列のコードが一致したら、コード名シートA5からk12の範囲をコピーし 1 2022/08/29 23:46
- Excel(エクセル) 別のシートの最終行の値を参照するには 5 2022/12/15 13:18
- Excel(エクセル) エクセルのマクロについて教えてください。 2 2023/02/26 13:19
このQ&Aを見た人はこんなQ&Aも見ています
-
新NISA制度は今までと何が変わる?非課税枠の拡大や投資対象の変更などを解説!
少額から投資を行う人のための非課税制度であるNISAが、2024年に改正される。おすすめの銘柄や投資額の目安について教えてもらった。
-
メニューバーのイベントが2回実行される
Visual Basic(VBA)
-
サイトの記事をエクセルに落としたいのですが・・・
Visual Basic(VBA)
-
VBAで変数の数/変数名を動的に変化させる
その他(プログラミング・Web制作)
-
-
4
ExcelVBAで複数条件で抽出して表を作成
Visual Basic(VBA)
-
5
1次元配列をワークシートに高速で転記する方法について質問します。
その他(Microsoft Office)
-
6
エクセルVBAの不思議な挙動?
その他(Microsoft Office)
-
7
Excel VBAのユーザーフォームでVLOOKUP
Visual Basic(VBA)
-
8
VBAのソースコードについて
Visual Basic(VBA)
-
9
ワークシートの特定範囲をパスワード付きでPDF保存するには?
Excel(エクセル)
-
10
VBA PivotItemをセルの中身で選択
Visual Basic(VBA)
-
11
エクセルvbaでdocuworksprinterの出力先を設定
Visual Basic(VBA)
-
12
【ExcelVBA】300万件越えCSVから条件を満たす行だけ抽出するには?
Visual Basic(VBA)
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
文字の色も参照 VLOOKUP
-
エクセルの保護で、列の表示や...
-
VBAで繰り返しコピーしながら下...
-
ExcelのVlookup関数の制限について
-
【条件付き書式】countifsで複...
-
Excel の複数シートの列幅を同...
-
Excel複数シートにあるデータを...
-
Excel VBA ピボットテーブルに...
-
excel 複数のシートの同じ場所...
-
VLOOKアップ関数の結果の...
-
エクセルVBAで、ある文字を含ん...
-
エクセル マクロ 標準モジュー...
-
Excel セルに入っている日付を...
-
【VBA】ピボットテーブルを既存...
-
SUMPRODUCTにて別シートのデー...
-
オートフィルタ使用時にCOUNTIF...
-
【VBA】シート名と見出しが一致...
-
Excelに自動で行の増減をしたい...
-
エクセルで横並びの複数データ...
-
エクセルの列の限界は255列以上...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
ExcelのVlookup関数の制限について
-
文字の色も参照 VLOOKUP
-
オートフィルタ使用時にCOUNTIF...
-
エクセルの保護で、列の表示や...
-
VBAで繰り返しコピーしながら下...
-
エクセル関数に詳しい方、教え...
-
【条件付き書式】countifsで複...
-
Excel の複数シートの列幅を同...
-
エクセル マクロ 標準モジュー...
-
エクセルで横並びの複数データ...
-
エクセルの列の限界は255列以上...
-
Excelでの並べ替えを全シートま...
-
VLOOKアップ関数の結果の...
-
SUMPRODUCTにて別シートのデー...
-
エクセルで、チェックボックス...
-
Excel VBA ピボットテーブルに...
-
【エクセル】1列のデータを交...
-
エクセルVBAで、ある文字を含ん...
-
エクセルのブック分割マクロを...
-
【VBA】複数のシートの指定した...
おすすめ情報