• ベストアンサー

ExcellVBAのFindに関する質問です。

お世話になります。 VBA超初心者です。 同じSheetに二つのテーブル 性別テーブル(名前を付けてます) 顧客ID 性別 SA081  男 SA083  男 SA010   女 SA013  女 顧客テーブル(名前を付けてます) ID 氏名    顧客ID 性別 1 山田 太郎  SA081 2 斉藤 清   SA082 3 山本 花子  SA061 です。 顧客テーブルの顧客IDを上から性別テーブルを検索して、あれば顧客テーブルの性別フィールドにその人の性別を記入するには、どうすればいいのでしょうか。 一生懸命考えて作ってはいるのですが、デバックばっかり出て、全然進みません。 Sub Chck() Dim k As Range, s, i Set k = Range("顧客テーブル").Range(2, 3).Value For i = 2 To myTbl.Rows.Count Set s = Range("性別テーブル").Cells.Find(what:=i, lookat:=xlPart, MatchCase:=False) If s Is Nothing Then k.Range("g2").Value 'ここに性別を書きます(ここは顧客テーブル外です。) Exit Sub End If Next End Sub 宜しくお願いします

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

  • ベストアンサー
  • hana-hana3
  • ベストアンサー率31% (4940/15541)
回答No.4

>それとも全部おかしいのでしょうか? yes・・・。 簡単な動作から覚えましょうw 最初のエラーがk.Range("g2").Valueですよね。 このままだと、k の内容はシートが指定されないといけませんが、 >Set k = Range("顧客テーブル").Range(2, 3).Value では全く別の値をオブジェクトに設定しています。 この設定にも誤りがあります。 おそらく、"顧客テーブル"と言う範囲を設定したいのでしょう。 この場合、シートのどこかに顧客テーブルという名前の範囲が設定されていれば、Set k = Range("顧客テーブル") と書けますが、Range(2, 3).Valueは余計です。 でも、書かれたソースでは役立たない値です。 >For i = 2 To myTbl.Rows.Count myTblが何処にも定義されていないので、参照不可でエラー。 >Set s = Range("性別テーブル").Cells.Find(what:=i, lookat:=xlPart, MatchCase:=False) If s Is Nothing Then Set s = Range("性別テーブル").Find(・・・・という書き方が良いでしょう。 でも、検査値が what:=i ではFor文が動かないので、検索しようが無いですね。 動いたとしても数値なので、顧客IDは入っていません。 >k.Range("g2").Value 一巡して、(仮に)Range("g2").Value = 検索値 では、毎回同じ位置に入ってしまいます。 個々の文を正しくしても、目的の通りに動作させることは不可能です。 >Exit Sub も、うまく動作したとしても1回目の検索で記入が終了してしまいます。 他の方法もあると思いますが下記のような物を書いて見ました。 'Find版 Sub ChckFind() Dim k As Range Dim Ct As Integer Dim s As Range For Each k In Range("顧客テーブル") '顧客テーブルの全ての値を取得 If InStr(k.Value, "顧客ID") = 1 Then Ct = k.Column '顧客IDが何列目にあるかを記録 If k.Column = Ct And k <> "" Then '顧客テーブルの列で、値が空白以外なら検索を行う Set s = Range("性別テーブル").Find(what:=k.Value, lookat:=xlPart, MatchCase:=False) If Not s Is Nothing Then '見つかった場合 '顧客IDの隣のセルに、性別テーブルで見つけた顧客IDの '隣のセルの値を記入。 k.Offset(0, 1) = s.Offset(0, 1) End If End If Next End Sub 'Vlookup版 Sub ChckVlookup() Dim k As Range Dim Ct As Integer Dim s As Variant On Error Resume Next 'エラーがあっても止まらないで実行 For Each k In Range("顧客テーブル") If InStr(k.Value, "顧客ID") = 1 Then Ct = k.Column If k.Column = Ct And k <> "" Then 'VLOOKUPを使って性別テーブルの値を取得 s = WorksheetFunction.VLookup(k.Value, Range("性別テーブル"), 2, False) If s <> "" Then '値が見つかったら記入する。 k.Offset(0, 1) = s End If End If Next On Error GoTo 0 'エラーが有ったら止まるように設定する。 End Sub 頑張ってくださいね。

sofut_me3
質問者

お礼

有難うございます。 本当に私のと全然違いますね。 For EachステートメントやInStr関数っていうのがあるなんて知りませんでした。 又色々質問すると思いますので、その時も宜しくお願いします。

その他の回答 (3)

  • papayuka
  • ベストアンサー率45% (1388/3066)
回答No.3

#2です。 書き忘れましたが、元のコードが lookat:=xlPart になってたので、そのままサンプルも書きましたが、xlWhole にしないと部分的に一致する値があった場合、先に見つけた方を拾ってしまいます。

sofut_me3
質問者

お礼

有難うございます。 本を見て勉強しているんですが、難しくって… 又質問すると思いますので、その時も宜しくお願いします。

  • papayuka
  • ベストアンサー率45% (1388/3066)
回答No.2

変数の型などを理解されていないようで、かなりの部分がおかしいと思います。 ↓kはRange型ですから代入するのであれば Set k = Range("顧客テーブル").Range(2, 3).Value      ↓ Set k = Range("顧客テーブル") のようにしないと成り立ちません。         ↓myTblってどこから出てきたのでしょう? For i = 2 To myTbl.Rows.Count ↓最初の i は For の指定だと 2 です。つまり 2 を含むものを探してます。 ~.Find(what:=i, lookat:=xlPart, MatchCase:=False)       ↓逆です。見つからなかった場合になっています。 If s Is Nothing Then     ↓文法的に変です。 k.Range("g2").Value '-------------------------------------------------------------------------- 上手く動くか解りませんがサンプルです。 試すならテスト環境で。 Sub Test() Dim tRange As Range, r As Range, fr Set tRange = Range("顧客テーブル").Offset(, 2).Resize(, 1) For Each r In tRange  Set fr = Range("性別テーブル").Resize(, 1).Find(what:=r, lookat:=xlPart)  If Not fr Is Nothing Then r.Offset(, 1).Value = fr.Offset(, 1).Value Next r End Sub

  • hana-hana3
  • ベストアンサー率31% (4940/15541)
回答No.1

VBAの問題以前に、データベースの作り方に誤りがあるような気がします。 顧客IDというのは一意なもので普遍ですから、これを顧客テーブルのIDに割り当てるべきかと思います。 そうすれば、単純にVLOOKUP関数で処理できます。 顧客ID 氏名     性別 SA081  山田 太郎 =VLOOKUP(~)   VBAで処理する必要は何でしょうか?

sofut_me3
質問者

補足

早速の回答有難うございます。 確かにそうですね。 何を一生懸命悩んでたんだろう。 ですが、一応勉強の為にマクロでの書き方を教えていただけますか。 k.Range("g2").Value の記述の仕方が間違っているんだと思うんですが。。。 それとも全部おかしいのでしょうか? 宜しくおねがいします。

関連するQ&A

  • For~Nextについて

    VBA勉強中です。 For~Nextについて、いまいちわからないので、教えてほしいのですが、 下記の表を作り、テーブルと言う名前を付けました。 C列に上からA.Bの値を入れようと思います。 | A | B |C 1| AA| 11| 2| AB| 12| Sub Macro1() Dim AA As Range, BB As Range, AB As Variant Dim myTbl As Range, myFld As Integer, i As Integer Set AA = Range("A1") 'AAの箱にA1の値を Set BB = Range("B1") 'BBの箱にB1の値を Set myTbl = Range("テーブル") 'myTblの箱にテーブルを myFld = 3 'myFldの箱に3列目 AB = AA & "." & BB 'A1とB1の値を入れる For i = 1 To myTbl.Rows.Count 'iはテーブルの1行目から最後の行まで If myTbl.Cells(i, myFld).Value = AB Then 'テーブルの1行目のCのセルにA1とB1の値を入れる Exit Sub End If Next End Sub と思うのですが、やはり動きません。 アドバイスをお願いします。

  • マクロで質問します。

    初心者です。 下記のようなマクロの式があるのですが、条件を一つ増やしたいのですが、 イロイロ試してみたのですが、うまくゆきませんので教えてください! Sub 給与支払一覧() Application.ScreenUpdating = False Dim Sh As Worksheet For Each Sh In Worksheets If Sh.Name <> "給与支払一覧" And Sh.Name Like "Sheet*" Then With Worksheets("給与支払一覧") If Sh.Range("D14").Value > 0 Then With .Cells(.Rows.Count, 1).End(xlUp).Offset(1) Sh.Range("O2:X14").Copy .Cells(1) .Resize(13, 10).Value = Sh.Range("O2:X14").Value End With End If End With End If Next Sh Set Sh = Nothing End Sub この中で If Sh.Range("D14").Value > 0 Then とありますが、 同じ条件で I14も 0より大きいな時としたいのですが、 うまくゆきませんでした。 たぶん基本できな簡単な事と思いますが 分かりません。 If Sh.Range("D14").Value > 0 Then If Sh.Range("I14").Value > 0 Then 並べてみたり If Sh.Range("D14、I14").Value > 0 Then こんなのや If Sh.Range("D14、I14").).Value > 0 Then このような事も 他にも笑われるようなことも・・・・・ よろしくお願いします。

  • ExcelからAccess2013DBを更新する時

    Excel2013 vba-> Access2013 mdbファイル 問題点:以下のソースを実行すると、エラーが発生します。このエラーをなくしてアクセスデータベースのテーブルの情報の更新、新規追加、削除を行いたいです。 エラー内容:実行時エラー'3251' 現在のRecordsetは更新をサポートしていません。プロバイダーか、選択されたロックタイプの限界の可能性があります。 ソース: Sub 登録処理()   Dim Rst As adodb.Recordset   Dim SQL As String   Dim Rg As Range   Dim RgData As Range   Dim lngLastRow As Long   Dim RgDel As Range      On Error GoTo errH      Set RgData = mySh.Range("B2")   lngLastRow = RgData.End(xlDown).Row   Set RgData = mySh.Range(RgData, mySh.Range("AB" & lngLastRow))      SQL = "Select * from [会社管理テーブル]"   Call DBconection2   Set Rst = New adodb.Recordset   With Rst     .ActiveConnection = Cn     'SQL文でテーブル名と抽出条件を指定する     .Source = SQL     .CursorLocation = 3 ' クライアントサイドカーソルに変更     .Open        End With      Dim y As Long      Sheets("会社管理").Select      If Rst.EOF = False And Rst.BOF = False Then          For i = 1 To RgData.Rows.Count              If Cells(i + 1, 1).Value = "変更" Then         Rst.MoveFirst         Rst.Find "[施工会社ID]=" & RgData(i, 1).Value         If Rst.EOF Then                    Else           Rst.Fields("会社ID").Value = RgData(i, 2).Value           Rst.Fields("会社名").Value = RgData(i, 3).Value           Rst.Fields("フリガナ").Value = RgData(i, 4).Value              Rst.Update         End If         Cells(i + 1, 1).Value = ""       ElseIf Range(i, 1).Value = "削除" Then         Rst.MoveFirst                  Rst.Find "[会社ID]=" & RgData.Cells(i, 1).Value         If Rst.EOF Then                    Else           Rst.Delete         End If         Set RgDel = Rows(i + 1 & ":" & i + 1)         RgDel.Select         RgDel.Delete                ElseIf Range(i, 1).Value = "新規" Then         Rst.AddNew         Rst.Fields("会社ID").Value = RgData(i, 2).Value         Rst.Fields("会社名").Value = RgData(i, 3).Value         Rst.Fields("フリガナ").Value = RgData(i, 4).Value         Rst.Update         Cells(i + 1, 1).Value = ""       End If            Next i        End If exitH:      Rst.Close: Set Rst = Nothing   Call DBclose2   Exit Sub         errH:   MsgBox Err.Number & "(" & Err.Description & ")"   GoTo exitH    End Sub Sub DBconection2()   Set Cn = New adodb.Connection   Cn.Provider = "Microsoft.Jet.OLEDB.4.0"   Cn.Open modPublic.DBPATH    End Sub Function MakeDBconection() As adodb.Connection   Set Cn = New adodb.Connection   Cn.Provider = "Microsoft.Jet.OLEDB.4.0"   Cn.Open modPublic.DBPATH      Set MakeDBconection = Cn    End Function Sub DBclose2()   Cn.Close   Set Cn = Nothing End Sub Sub EraseContents(s_Rg As Range)   s_Rg.ClearContents    End Sub 誰か、解決方法がおわかりの方がいましたら、アドバイスをよろしくお願いします。

  • 2つのVBAを組み合わせる方法

    お世話になります、2つのVBAを組み合わせる方法で迷っています。 1つ目が Private Sub Worksheet_Change(ByVal Target As Range) Dim i As Long, k As Long, myNum As Long If Intersect(Target, Range("C1,B9:B39")) Is Nothing Or Target.Count > 1 Then Exit Sub Application.EnableEvents = False With Target If .Column = 3 Then myNum = WorksheetFunction.Max(Range("B9:B39")) If IsDate(.Value) Then For i = 9 To 39 If Cells(i, "A").Value = "" Then Cells(i, "B").Value = "" Else Cells(i, "B") = myNum + i - 8 End If Next i End If Else i = .Row If .Value = "" Then Range(Cells(i + 1, "B"), Cells(39, "B")).ClearContents Else For k = i + 1 To 39 If Cells(k, "A").Value = "" Then Cells(k, "B").Value = "" Else Cells(k, "B") = Cells(k - 1, "B") + 1 End If Next k End If End If End With Application.EnableEvents = True End Sub です。 2つめが Private Sub Worksheet_Change(ByVal Target As Range)  Application.EnableEvents = True If Intersect(Target, Range("R8:R38")) Is Nothing Then Exit Sub Application.EnableEvents = False Range(Cells(Target.Row, 18), Cells(39, 18)).Value = Target.Value Application.EnableEvents = True End Sub です。2つのPrivate Sub Worksheet_Change(ByVal Target As Range)イベントのVBAですが、どのようにして組み合わせれば良いのでしょうか?

  • Find,Offsetを使ってセルを指定する方法

    エクセルVBAのことで伺います。 以下の記述は、「D3からQ3までのセルの中で「年」と入ったセルの左横のセルを探し、 その中の値(西暦の年が入っています)を、G4からI100までの範囲に入力される月日 の年として置き換える」といったものなのですが、エラーが出てしまいます。 「実行時エラー424、オブジェクトが必要です。」とのメッセージが表示され、デバックを クリックすると、「Set FoundCell = Range("D3:Q3").Find("年").Offset(0, -1).Select」 が黄色く強調表示されています。 プログラムの記述をどのように修正すれば良いか、どなたかお教えください。 よろしくお願いいたします。 Private Sub Worksheet_Change(ByVal Target As Range) Dim FoundCell As Range Set FoundCell = Range("D3:Q3").Find("年").Offset(0, -1).Select With Target If Intersect(Target, Range("G4:I100)) Is Nothing Or Target.Count <> 1 Then Exit Sub If IsDate(.Value) Then If Year(.Value) <> FoundCell Then Application.EnableEvents = False .Value = DateSerial(FoundCell, Month(.Value), Day(.Value)) Application.EnableEvents = True End If End If End With End Sub

  • マクロのFINDメソッドで質問です。

    マクロの初心者で、いつもお世話になっております。 FINDメソッドを使って別々のシートから同じIDを探す処理をしたいのですが、IDが片方にしか無い場合に検索2rangeが"nothing"になってしまい止まってしまいます。 抜粋ですか以下の様にコーディングしました。 解る方がいましたらアドバイスをお願いします。 IDはIDがセットされている列です。 シート2を上から1つずつ見ていき、 シート1から該当するIDを探す処理をします。 最終的には該当したIDの行数を記憶して、 シート1とシート2をマッチングさせたいのですが。 Dim 検索range As Range Dim 検索2range As Range ID = Sheet2.Cells(LOOP_C1, 検索列).Value Set 検索Range = Range(Sheet1.Cells(F2TOP,検索列),Sheet1.Cells(LASTRow, 検索列)) Set 検索2range = 検索Range.Find(What:=ID, LookAt:=xlWhole, SearchOrder:=xlByRows, searchformat:=True).Row ※ If 検索2range Is Nothing Then Else   検索2range.Activate End If ・ ・ ・ ※の箇所で止まってしまいます。

  • すべてのシートでマクロを実行したい

    以下のプログラムでは、選択したシートのみマクロが動作しています。ネット検索で見よう見まねで作ったため何がまちがっているのかわかりません。ご教示いただけるとありがたいです。 ・月の予定表で利用者が休みの日に斜線を引くマクロ ・入力ミスを防ぐためシート保護をしている Sub すべてのシート() Dim s As Worksheet For Each s In Worksheets s.Select Call 斜線 Next End Sub Sub 斜線() ActiveSheet.Unprotect Password:="1234" For i = 1 To Range("E10").End(xlDown).Row Range("AS" & i).Borders(xlDiagonalUp).LineStyle = xlNone If Range("E10").Value = 0 Then Exit Sub If Cells(i, "E").Value = "日" And Range("BP9").Value = 0 Then Range("AS" & i).Borders(xlDiagonalUp).LineStyle = xlContinuous End If If Cells(i, "E").Value = "月" And Range("BP10").Value = 0 Then Range("AS" & i).Borders(xlDiagonalUp).LineStyle = xlContinuous End If If Cells(i, "E").Value = "火" And Range("BP11").Value = 0 Then Range("AS" & i).Borders(xlDiagonalUp).LineStyle = xlContinuous End If If Cells(i, "E").Value = "水" And Range("BP12").Value = 0 Then Range("AS" & i).Borders(xlDiagonalUp).LineStyle = xlContinuous End If If Cells(i, "E").Value = "木" And Range("BP13").Value = 0 Then Range("AS" & i).Borders(xlDiagonalUp).LineStyle = xlContinuous End If If Cells(i, "E").Value = "金" And Range("BP14").Value = 0 Then Range("AS" & i).Borders(xlDiagonalUp).LineStyle = xlContinuous End If If Cells(i, "E").Value = "土" And Range("BP15").Value = 0 Then Range("AS" & i).Borders(xlDiagonalUp).LineStyle = xlContinuous End If If Cells(i, "AY").Value = "祝日" And Range("BP16").Value = 0 Then Range("AS" & i).Borders(xlDiagonalUp).LineStyle = xlContinuous End If Next i ActiveSheet.Protect Password:="1234" End Sub

  • comboboxで任意の行列を削除する

    comboboxで選択したデーターを探して、その行の 2列目から45列までを、削除する方法をお教えください。 下のように記述したのですが、1行全てが削除されてしまいます。 どのように記述したらよいのでしょうか。 よろしくお願いします。 Private Sub 保存データー削除_Click() Dim i As Long For i = 2 To 199 If Cells(i, 2).Value = combobox1.Value Then Range(i & ":" & i).Delete End If Next i Dim k As Long, s As Long k = 1 For s = 1 To 31 Cells(s, 1).Value = k k = k + 1 Next s End Sub

  • エクセルのデータの変更

    今マクロでSheet1にあるデーターをSheet2・3・4・5・6・7それぞれにそれぞれの抽出条件で抽出できるよう設定してあるのですが、このSheet1を他のBookに変更した場合のマクロの変更の仕方を教えてください。 ちなみにいまは 標準モジュールに Sub 定義() Dim myTbl As Range, myQry As Range, sakiRng As Range End Sub と各シートの[Worksheet Activate] に Private Sub Worksheet_Activate() Set myTbl = Sheets(1).Range("myTbl") Set myQry = Sheets(8).Range("A_抽出条件") Set sakiRng = Sheets(2).Range("A3:AR3") myTbl.AdvancedFilter xlFilterCopy, myQry, sakiRng Dim rw As Long '入力最終行 rw = Range("I65536").End(xlUp).Row With Application Range("I" & rw + 1) = .Sum(Range("I1:I" & rw)) Range("AO" & rw + 1) = .SumIf(Range("AP1:AP" & rw), "済", Range("AO1:AO" & rw)) Range("AQ" & rw + 1) = .Sum(Range("AQ1:AQ" & rw)) End With End Sub となっています。

  • 再質問 長いIF文を短くしたい

    お世話になっております 先日1/24に、条件を示さずに「長いIF文を短くしたい」という質問をしてしまいました こちらの手抜きをお詫びします 前回keithinさんにアドバイスいただいた方法で書き直しましたので これをさらに簡単に書く方法があれば教えてください 以下は、Private Sub Worksheet_Change(ByVal Target As Range)内のマクロです If Target.Row >= 15 And Target.Row <= 100 And Target.Column = 9 Then If Range("I" & Target.Row).Value < Range("J" & Target.Row).Value Then If Range("G" & Target.Row).Value >= 1 Then If Range("I" & Target.Row).Value >= Range("G" & Target.Row).Value Then If Range("I" & Target.Row).Value Mod Range("G" & Target.Row).Value = 0 Then  処理 End If End If End If End If End If

専門家に質問してみよう