VBAでVLOOKUP関数のように動作させたい

このQ&Aのポイント
  • VBA初心者の者がVBAでVLOOKUPのような機能を実装したいです。具体的には、指定した範囲内で検索値と一致するセルの値を取得する処理です。
  • 現在のコードでは、参照範囲が1ずつ増加してしまうため、常に指定した範囲内を参照させたいという問題があります。
  • ワークシート関数を使用せずに解決する方法を教えていただけないでしょうか?
回答を見る
  • ベストアンサー

VBAでVLOOKUP関数のように動作させたい

VBA初心者の者です。 勉強として、VBAでVLOOKUPのよう作動させてみようと思い、以下のようにコードを書きました。 Sub 試験() Dim i As Integer, mx As Integer mx = 2 For i = 2 To 10 If Worksheets("Sheet2").Cells(mx, 1) = Worksheets("Sheet1").Cells(i, 1) Then Worksheets("Sheet2").Cells(mx, 2).Value = Worksheets("Sheet1").Cells(i, 2).Value mx = mx + 1 Else Worksheets("Sheet2").Cells(mx, 2).Value = 0 mx = mx + 1 End If Next i End Sub ※sheet1が参照範囲、sheet2が検索値です。 これを実行させたところ問題にきづきました。 sheet1の参照範囲がループによって1ずつ増加していく点です。 (ループ一周目の参照範囲 A2~A10) (ループ二週目の参照範囲 A3~A10) 上記のように参照範囲を1ずつ増加させず、常に sheet1 のA2からA10 まで 参照させたいのですが、どのようにすればよいのでしょうか? ワークシート関数は使わない方向で考えています。 アドバイスお願い致します。

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

  • ベストアンサー
  • hallo-2007
  • ベストアンサー率41% (888/2115)
回答No.3

No1です。とりあえずVBAの勉強という事で >ご回答下さった二重ループだと、どのような動きになるのでしょうか? mx = 2 For i = 2 To 10 Worksheets("Sheet2").Cells(mx, 2).Value = 0 If Worksheets("Sheet2").Cells(mx, 1) = Worksheets("Sheet1").Cells(i, 1) Then Worksheets("Sheet2").Cells(mx, 2).Value = Worksheets("Sheet1").Cells(i, 2).Value End If Next i だった場合 Sheet2のB2セルをとりあえず 0にする。 Sheet2の2行目の値がSheet1の1~10行目と同じときに、そのB列の値がSheet2のB2に入ります 同じ値がなければ、そのまま 0が残ります。 次に mx = 3 の時を考えます。 Sheet2のB3セルをとりあえず 0にする。 Sheet2の3行目の値がSheet1の1~10行目と同じときに、そのB列の値がSheet2のB3に入ります 同じ値がなければ、そのまま 0が残ります。 これを、mxが10まで繰り返してくれるように (この動作を、Sheet2の2行目から10行目まで繰り返すために) For mx = 2 To 10 For i = 2 To 10 ここで、Sheet1の2行目から10行目までの口返し Next i Next mx つまり Sheet1の2~10までの8回の繰り返しを Sheet2の2~10まで8回繰り返し。 途中のIF文は 8*8の64回実行されます。

yuzuzx
質問者

お礼

なるほど! 二重ループなるものがおそらく理解できたと思います。 一つ一つの動作を丁寧に教えていただいてありがとうございます。 For~Nextの理解が乏しいが故に勘違いに気づきました。 教えていただいたコードを理解して上で活用させていただきたいと思います。 ただ、実際の在庫管理では10000アイテム以上あるので、かなり処理に時間かかりそうです… また、いい方法模索してみます。

その他の回答 (2)

  • Siegrune
  • ベストアンサー率35% (316/895)
回答No.2

>sheet1の参照範囲がループによって1ずつ増加していく点です。 本当にそうなっていますか?(たまたまなのでは?) 例えば、 sheet2の1行目は、sheet1の5行目にヒットする。 sheet2の2行目は、sheet1の3行目にヒットする。 というデータで試してみてください。 2行目は見つからないはずです。 なぜかって? If Worksheets("Sheet2").Cells(mx, 1) = Worksheets("Sheet1").Cells(i, 1) Then Worksheets("Sheet2").Cells(mx, 2).Value = Worksheets("Sheet1").Cells(i, 2).Value mx = mx + 1 Else Worksheets("Sheet2").Cells(mx, 2).Value = 0 mx = mx + 1 End If としているので、見つかったら、sheet2の次の行を、sheet1の見つかった行から 探しに行くようにしているからです。 sheet2の1行目は、sheet1の10行目にヒットする。 sheet2の2行目は、sheet1の1行目にヒットする。 sheet2の3行目は、sheet1の2行目にヒットする。 ・・・ で試してみてください。結果は、1行目以外はみんな0のはずです。 sheet2の1行目から、n行目に対して、毎行、 sheet1の2行目から10行目をチェックするということをしたいと思われるので、 sheet1のチェックをしている行iと、sheet2の対象行mxはそれぞれ、 for~nextで繰り返す必要があるということで、ANo.1の方が回答を書かれているはずです。 他にdo loopでする方法やifで条件が成立したらexit forで抜けたほうが早いなど もろもろあるのですが、まあ今回は割愛させていただいて。 で、そもそもの >sheet3で統合した商品コードでVLOOKUPをかけた際、前期に在庫があり、当期に在庫がない場合、>sheet3の当期数量欄に参照先エラーが返されてしまいます。 ですが、こういうときは、 if(isna(vlookup(A10,前期!A:B,2,false))=true,0,vlookup(A10,前期!A:B,2,false)) + if(isna(vlookup(A10,当期!A:B,2,false))=true,0,vlookup(A10,当期!A:B,2,false)) という形の式を使います。 isna(・・・)は、・・・のvlookup関数が見つからなくて#N/Aを返したときtrueになるので、 そのときは0を代入するという意図です。

yuzuzx
質問者

お礼

おっしゃる通りのような現象になってしまい、困っていました。 日本語力不足ですみません。 丁寧に説明していただきありがとうございます。

  • hallo-2007
  • ベストアンサー率41% (888/2115)
回答No.1

どういう結果がご希望なのかわかりませんが、ひょっとして Sub 試験() Dim i As Integer, mx As Integer For mx = 2 To 10 For i = 2 To 10 Worksheets("Sheet2").Cells(mx, 2).Value = 0 If Worksheets("Sheet2").Cells(mx, 1) = Worksheets("Sheet1").Cells(i, 1) Then Worksheets("Sheet2").Cells(mx, 2).Value = Worksheets("Sheet1").Cells(i, 2).Value End If Next i Next mx End Sub といったように、二重のループが必要かな? Elseの時に Worksheets("Sheet2").Cells(mx, 2).Value = 0 も意味が分かりませんでしたので、移動させました。

yuzuzx
質問者

補足

ご回答ありがとうございます。 説明不足があってすみません。 二期間の商品在庫変動で活用できればなと思い検討中です。 本来はsheet1に前期在庫、sheet2に当期在庫、sheet3に前期と当期の商品コードを統合したものを用意し、VLOOKUPでSheet3に各期の在庫数をひっぱっています。 在庫数がゼロの場合は前期在庫・当期在庫にはその商品コードが生じません。 そのため、sheet3で統合した商品コードでVLOOKUPをかけた際、前期に在庫があり、当期に在庫がない場合、sheet3の当期数量欄に参照先エラーが返されてしまいます。 つまり、VBAを使った際にもsheet3にある商品コードがsheet1若しくはsheet2にないケースがあります。 その際に0を入力させるために以下のコードを入力しています。 Worksheets("Sheet2").Cells(mx, 2).Value = 0 ご回答下さった二重ループだと、どのような動きになるのでしょうか? 条件分岐が一周すると 変数i は 1増加してしまいそうなのですが… 変数iは何度ループされても 2 to 10 を常に検索するようにしたいと考えています。 (ループ使うべきではないのかもしれませんが、対処方法がわかりません。) 変数mx はループごとに1ずつ増加することで問題はありません。 説明下手ですみません。

関連するQ&A

  • VBA Next For でのコピペについて

    EXCEL VBA初心者です。 AシートEW44からGD44までをコピーしてBというシートの最終行へコピーしたいです。 今下記のように組んでいるのですが、うまく作動しません。 Private Sub CommandButton1_Click() Dim i As Integer For i = 153 To 186 row1 = Worksheets("B").Cells(Rows.Count, 27).End(xlUp).Row Worksheets("A").Cells(i, 44).Value = Worksheets("B").Cells(row1 + 1, 27).Value Next i End Sub アドバイスいただけませんでしょうか。

  • VBAでVlookup関数を組もうとしていますがエラーが出ます。VBAに詳しい方、教えてください

    VBAでvlookup関数を下のように組みましたが、(1)でエラーが出ます。VBAに詳しい方、教えてください。 Sub VLLOKUPによる表の検索4() Dim mykensakuchi Dim mykensakuhan Dim gyo As Integer (1) mykensakuchi = Worksheets("sheet1").Range("a" & gyo).Value mykensakuhan = Worksheets("sheet2").Range("b2:e9") saikagyo = Worksheets("sheet1").Range("a" & Rows.Count).End(xlUp).Row gyo = 2 For gyo = saikagyo To 1 Step -1 With Application.WorksheetFunction Range("b:gyo").Value = .VLookup(mykensakuchi, mykensakuhan, 2, False) End With Next End Sub

  • VBAで空欄にデータに表示

    エクセルVBAのIFを使って、シートaのA列に値があって、B列が空欄の場合のみ、空欄のセルにシートbの値を表示させたいです。 上手くできませんでしたので、教えてください。 Sub Do文2() Dim i As Integer i = 1 If Worksheets("a").Cells(i, 2) = "" Then Do While Worksheets("a").Cells(i, 1) <> "" Worksheets("a").Cells(i, 2) = Worksheets("b").Cells(1, 1) i = i + 1 Loop End If End Sub

  • VLOOKUP関数と同じことをVBAでおこなうには

     初めまして、当方VBAの素人です。よろしくお願いします。  同じような質問で、このようなVBAを見つけました。 Sub Macro1() For n = 2 To 5 '処理するSheet2の行数範囲 a = Sheets("Sheet2").Cells(n, 1) 'aにA列の値を代入 For m = 2 To 5 '検索するSheet1の行数範囲 If Sheets("Sheet1").Cells(m, 1) = a Then 'Sheet2のA列の値とSheet1のA列が一致した場合 v = Sheets("Sheet1").Cells(m, 2) 'vにB列の値を代入 Sheets("Sheet2").Cells(n, 2).Value = v 'Sheet2のB列に値を入力 Exit For '値が見つかったのでForを終了 End If Next Next End Sub このVBAではSheet2での検索、入力が列になるのですが、列でなく、行でできないでしょうか。できればSheet1のB列の値をSheet2の1行で検索、Sheet2の2行に入力されるだけではなく、Sheet1のC列の値をSheet3の1行で検索、Sheet3の2行に入力されるようにしたいと思います。  解る方、よろしくお願いします。

  • 全くの初心者ですVBA

    どこが悪いかわかりません。 教えてください。 Sub テスト() Dim kekka As String Dim i As Integer tokuten = Worksheets("Sheet1").Cells(i, 1).Value For i = 1 To Worksheets("Sheet1").Range("A1").End(xlDown).Row.Count If tokuten >= 80 Then kekka = "合格" Else kekka = "不合格" kekka = Cells(i, 2) End If Next i End Sub シート1の A列に数値で得点が入っています。

  • VBAで関数を使うには?

    こんな感じだったとします。   A1      B1 2002/9/2 2002/9/3 2002/9/4 2002/9/5   : このB1にそれぞれの曜日を表示させるVBAを以下のようにしました。 Sub youbi() Dim i As Integer For i = 3 To 10 Cells(i, 3).Value = Weekday(Cells(i, 2), "aaa") Next End Sub もちろんエラーでした。 (メッセージは「型が一致しません」です。) そこで以下のように変更しました。 Sub youbi() Dim i As Integer For i = 3 To 10 Cells(i, 3).Value = "=text(Weekday(b3), ""aaa"")" Next End Sub するときちんと曜日が表示されたのですが、もちろん全部B3のセルの日付の曜日です。 ここを変数にするにはどうしたらいいのでしょうか? とっても簡単なことのように思えますが、意外とハマってしまって抜け出せません。 よろしくお願いします。

  • Excel VBAシートの同一番地のセルのリスト化

    別々のシートの同一番地のセルの値をリスト化するのにこのようなVBAを見つけました。 シートは追加せず、既存のシートを指定したくて、色々と書き換えをチャレンジしましたがうまくいきません。 既存のシートを指定し、この作業を行うにはどうしたらよいのでしょうか? ご教示いただけますと幸甚です。 Sub Test1() Dim TmpSheet As Worksheet, i As Integer i = Worksheets.Count Set TmpSheet = Worksheets.Add(After:=Sheets(Sheets.Count)) With TmpSheet For i = 1 To i .Cells(i, 1).Value = Worksheets(i).Name .Cells(i, 2).Value = Worksheets(i).Range("E5").Value Next End With End Sub

  • EXCEL2003 VBAで動作が速くなるようにマクロ記述したいのです

    EXCEL2003 VBAで動作が速くなるようにマクロ記述したいのですが、どのように行えばいいのでしょうか? Sheet1のA1からA300まで、関数によって計算されたデータが格納されています。 そのA1からA300の値(関数の計算結果のみ)を、コマンドボタンをクリックした時にSheet2のA1からA300にコピーしています。 コマンドボタンをクリックする度に、Sheet1のA1からA300までの値を、Sheet2に列を変えてコピーし、値を蓄積する方法を取っています。 以下のマクロを記述して走らせてみましたが、動作が遅いのが気になります。 コピーして貼り付けている動作が遅くなっているのでしょうか? もう少し早くなる方法はありますでしょうか? よろしくお願いします。 Sub CommandButton1_Click1() Dim I Dim N Worksheets("sheet1").Range("F1").Value = Range("F1").Value + 1 N = Worksheets("sheet1").Range("F1").Value For I = 1 To 300  Application.ScreenUpdating = False   Worksheets("sheet1").Cells(I, 1).Copy   Worksheets("sheet2").Cells(I, N).PasteSpecial Paste:=xlValues  Application.ScreenUpdating = True Next End Sub

  • VBA リストボックスについて

    VBA初心者です。どうぞよろしくお願いします。 ユーザーフォームにタブつきのリストボックスを作りたいと思っています。 リストはsheet1の中にあります。   A    B    C    D・・・ 1  NO  品名  売場 2  1  いちご  果物 3  2  みかん  果物 4  3  もも    果物 5  4  ハクサイ 野菜 6  5  キャベツ  野菜 7  6  きゅうり  野菜 8  7 9 果物のタブには、果物の品名が表示される。 1 いちご 2 みかん 3 もも 野菜のタブには、野菜の品名が表示される。 4 ハクサイ 5 キャベツ 6 きゅうり 青果のタブには、果物、野菜が表示される。 1 いちご 2 みかん 3 もも 4 ハクサイ 5 キャベツ 6 きゅうり 本を見ながら格闘しておりますが、きっと的違いで滅茶苦茶なことをしているのだと思います。 どうにも出来ず困っております。どなたか教えていただけないでしょうか。よろしくお願いします。 Private Sub UserForm_Initialize() Dim LastRow As Long Dim i As Integer Dim ListBoxNo As Integer Dim ListBox As Control Dim Listtabu(3) As Long 'タブの数 For i = 1 To 3 Listtabu(i) = 0 Next i Worksheets("sheet1").Activate With Worksheets("sheet1") LastRow = .Range("A65536").End(xlUp).Row For i = 2 To LastRow If Worksheets("sheet1").Range(Cells(i, 3)) = "果物" Then ListBoxNo = 1 Set ListBox = 果物 果物.List = Worksheets("sheet1").Range(Cells(i, 1), Cells(i, 2)).Value End If If Worksheets("sheet1").Range(Cells(i, 3)) = "野菜" Then ListBoxNo = 2 Set ListBox = 野菜 野菜.List = Worksheets("sheet1").Range(Cells(i, 1), Cells(i, 2)).Value End If If Worksheets("sheet1").Range(Cells(i, 3)) = "果物" & "野菜" Then ListBoxNo = 3 Set ListBox = 青果 青果.List = Worksheets("sheet1").Range(Cells(i, 1), Cells(i, 2)).Value End If ListBox.AddItem ListBox.List(Listtabu(LstBxNo), 0) = Worksheets("sheet1").Cells(i, 1).Value ListBox.List(Listtabu(LstBxNo), 1) = Worksheets("sheet1").Cells(i, 2).Value Listtabu(LstBxNo) = Listtabu(LstBxNo) + 1 Next End With End Sub

  • ExcelのVBAについての質問です。

    ExcelのVBAについての質問です。 計測機器をつないでsheet1に数値が書き込まれていってる状況です。下記のプログラムを特定の時間内に複数回ループされるように設定したいのですが、そのようなプログラムを加えればいいのでしょうか? Sub Macro1() ' ' Macro1 Macro ' ' Dim iRows As Integer Dim sRows As String ' 最終行の調査: iRows = Worksheets("Sheet1").UsedRange.Rows.Count ' 最終行をシート3にコピー Worksheets("Sheet1").Rows(iRows).Copy Destination:=Worksheets("Sheet3").Range("1:1") ' CH1 の最新データをシート3にコピー Worksheets("Sheet3").Range("B4").Value = Worksheets("Sheet1").Cells(iRows, 3).Value ' CH2 の最新データをシート3にコピー Worksheets("Sheet3").Range("B5").Value = Worksheets("Sheet1").Cells(iRows, 4).Value End Sub

専門家に質問してみよう