Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10 Home : Excel 2021)
Match関数で、完全一致しない値がヒットしてしまう
投稿日時: 23/05/04 17:22:22
投稿者: タークン
メールを送信

     myColumns = 0
     On Error Resume Next
      sch = "external_product_id_typ"
      myColumns = WorksheetFunction.Match(sch, Range(.Cells(3, 1), .Cells(3, rc)), 0)
      If myColumns = 0 Then
          Debug.Print sch
        Else
           i13 = myColumns
       End If
 
で、"external_product_id_typ"の文字列が存在する列番号を検索すると、
ひとつ左隣の、"external_product_id"がヒットしていまい、
ひとつ少ない列番号を取得してしまいます。
 
解決方法が、全く思い当たりません。
解決可能なのでしょうか?
 

回答
投稿日時: 23/05/04 17:50:49
投稿者: 半平太

> .Cells(3, 1)
  ↑
このドットの頭に何があるんですか?(ちゃんと示して貰わないと部外者は分からないです)
多分、それが2列目から始まっているんじゃないですか。

回答
投稿日時: 23/05/04 18:35:10
投稿者: WinArrow
投稿者のウェブサイトに移動

>myColumns = WorksheetFunction.Match(sch, Range(.Cells(3, 1), .Cells(3, rc)), 0)
 
↑このコードは、実際に動作していますか?
動いているとしたら、掲示板には手入力していませんか?
 
実際のコードを掲示してください。

投稿日時: 23/05/04 18:50:17
投稿者: タークン
メールを送信

lここ以外は、正常に動いています。
実際には、i1〜i26までありますが、
問題になっている箇所2つだけ抜粋します。
 
    With Sheets("出品")
     rc = .Cells(3, Columns.Count).End(xlToLeft).Column
 
      sch = "external_product_id"
      myColumns = WorksheetFunction.Match(sch, Range(.Cells(3, 1), .Cells(3, rc)), 0)
      If myColumns = 0 Then
          Debug.Print sch
        Else
           i12 = myColumns
       End If
       
      sch = "external_product_id_typ"
      myColumns = WorksheetFunction.Match(sch, Range(.Cells(3, 1), .Cells(3, rc)), 0)
      If myColumns = 0 Then
          Debug.Print sch
        Else
           i13 = myColumns
            Debug.Print sch, i13
            MsgBox i13
       End If
    End With

回答
投稿日時: 23/05/04 19:18:49
投稿者: 半平太

当初の質問では、On Error Resume Nextが入っていましたよね?
 
今でもそのステートメントは入っていますね?
 
なら、"external_product_id_typ"が5列目に存在しないってことでしょう。
エラーになったので、前回成功した4がそのままmyColumnsに残った。
 
念の為、関数で計算する直前に初期化してみてください。
> sch = "external_product_id_typ"
    myColumns = 0  ’←初期化
> myColumns = WorksheetFunction.Match(sch, Range(.Cells(3, 1), .Cells(3, rc)), 0)

回答
投稿日時: 23/05/04 19:26:45
投稿者: simple

こういう場合もあるので、Application.Matchを使うほうがよいかもしれません。
 
こちらのサイトの即効テクニックの
https://www.moug.net/tech/exvba/0100035.html
のサンプル3の書き方が参考になるでしょう。

回答
投稿日時: 23/05/04 19:29:17
投稿者: simple

私のコメントは誤解を招くかもしれません。
WorksheetFunction.Matchがダメというのではなく、
On Error Resume Nextの理解が乏しいと、間違った判断をしてしまいやすい、という話です。
既に適切な指摘をいただいていました。

回答
投稿日時: 23/05/04 21:37:39
投稿者: WinArrow
投稿者のウェブサイトに移動

引用:
myColumns = WorksheetFunction.Match(sch, Range(.Cells(3, 1), .Cells(3, rc)), 0)

 
>With Sheets("出品")
で、修飾しているから
Range(〜

.Range(〜
ピリオドをつける必要があります。

回答
投稿日時: 23/05/04 22:31:16
投稿者: WinArrow
投稿者のウェブサイトに移動

↑の「Rangeでピリオドを省略(記述漏れ)した場合のテストを大名いました。
>myColumns = 0
を「0」ではなく、敢えて「10」をせて押しました。
  
結果、
「Range」にピリオドがないので、その時点のアクテイブシートを参照しています。
そのアクティブシートに、検索キーが存在しなければ、
myColumnsの値は、変化しません、
そのアクティブシートに、検索キーが存在すれば
myColumnsの値は、ヒットした値が返ります。
 
WorksheetFunction
を使っても
Applicatio
を使っても同じです。

回答
投稿日時: 23/05/04 22:57:01
投稿者: 半平太

WinArrowさん
 
そのテストコードはどこに書いて実行したんですか?
 
標準モジュールならRangeの前にピリオドがなくても何も問題はないですよ。
2つの引数の方に漏れなく付けているんですから。

回答
投稿日時: 23/05/05 07:46:45
投稿者: WinArrow
投稿者のウェブサイトに移動

半平太 さんの引用:
WinArrowさん
 
そのテストコードはどこに書いて実行したんですか?
 
標準モジュールならRangeの前にピリオドがなくても何も問題はないですよ。
2つの引数の方に漏れなく付けているんですから。
再確認の結果、Rangeの前にピリオドがなくても、問題ないことが分かりました。
   
質問者さんへ
   
本件に関する私のレスは無視してください。
   
既にご指摘があるように、
エラートラップの「Resume Next」 は注意する必要があります。
(意図しないことにつながる可能性あり)
   
私が使っている方法を紹介します(エラートラップは使わない方法です。)
検索範囲にセル範囲ではなく、行を使っています。
   
    sch = "external_product_id_typ"
    If WorksheetFunction.CountIf(.Rows(3), sch) > 0 Then
        myColumns = WorksheetFunction.Match(sch, .Rows(3), 0)
     '以下省略
    End If

投稿日時: 23/05/05 15:00:57
投稿者: タークン
メールを送信

皆様、ご協力ありがとうございました。
ご指摘いただいた事を、すべて試した結果、改善されなかったので、
external_product_id_typeの検索順位を最初に持ってきて、
external_product_idを検索する間隔をあけた結果、
すべて正しい列番号が取得できました。
 
external_product_id_typの検索の際、
正しい文字列が代入されていた事は、
Debug.Print sch, i13で確認済みです。
 
      If WorksheetFunction.CountIf(.Rows(3), sch) > 0 Then
        myColumns = WorksheetFunction.Match(sch, .Rows(3), 0)
         i13 = myColumns
         Debug.Print sch, i13
           MsgBox i13
      End If
 
今回の事だけに関していえば、テレビを叩いて気合を入れるような方法で解決しましたが、
検索対象が、external_product_id_typeと、external_product_idだけだった場合は対処できず、
一度は、目視で正しく処理されているか否かを確認しなければならない状況は変わりません。
 
もしかしたら、EXCELL VBAのバグなのかもしれなと思っておりますが、
EXCELLで処理しなければならないものもあるので、
詳しい方がいらっしゃいましたら、アドバイス頂きたいと思います。
 
また、よろしくお願い致します。

回答
投稿日時: 23/05/05 15:25:55
投稿者: 半平太

>external_product_id_typeの検索順位を最初に持ってきて、
>external_product_idを検索する間隔をあけた結果、
>すべて正しい列番号が取得できました。

>external_product_id_typの検索の際、
>正しい文字列が代入されていた事は、
>Debug.Print sch, i13で確認済みです。
 
一体どっちが正しいの?
 
当初のコードの検索値は、"external_product_id_typ"
最終的に使った検索値は、"external_product_id_type" でしょ?
                                                ↑

投稿日時: 23/05/05 15:35:47
投稿者: タークン
メールを送信

両方とも存在します。
そして、続けて検索するとバグり、
間隔をあけると、2つとも正常な値を取得します。
これは、
     myColumns = 0
     On Error Resume Next
を使用しない方法でも、同じ結果でした。
 
コードの問題が無いとすると、こういう問題が起こりうるという実例になるかと思います。

回答
投稿日時: 23/05/05 16:21:00
投稿者: 半平太

> myColumns = 0
> On Error Resume Next
>を使用しない方法でも、同じ結果でした。
 
そんな案は横道なので、この際邪魔なだけです。
 
当初のコードに戻し、 On Error Resume Next だけ消去して、
どこで止まるのか先ず確かめてください。

投稿日時: 23/05/05 17:36:36
投稿者: タークン
メールを送信

違う文字列をヒットさせてしまうので、止まらないのです。
止まらずに、external_product_idを、external_product_id_typeと認識して、
external_product_idの列番号を取得してくるのです。

回答
投稿日時: 23/05/05 19:56:28
投稿者: 半平太

>違う文字列をヒットさせてしまうので、止まらないのです。
  
なるほどー
  
エラーが捕捉できないのか、誤ヒットなのか切り分けができないので、
取り敢えず以下のコードを実行してみてください。
  
1.Msgboxに何と出ますか?(イミディエイトウィンドウにも出ます)
2.どのステートメントで止まりますか?(それとも、またしても止まらないですか?)
  
Sub test()
    Dim rc, sch, myColumns, i12, i13, msg
     
    With Sheets("出品")
        rc = .Cells(3, Columns.Count).End(xlToLeft).Column
         
        sch = "external_product_id"
        myColumns = WorksheetFunction.Match(sch, Range(.Cells(3, 1), .Cells(3, rc)), 0)
        i12 = myColumns
         
        sch = "external_product_id_typ"
        myColumns = WorksheetFunction.Match(sch, Range(.Cells(3, 1), .Cells(3, rc)), 0)
        i13 = myColumns
         
        myColumns = WorksheetFunction.HLookup(sch, Range(.Cells(3, 1), .Cells(3, rc)), 1, False)
         
        msg = i12 & "列目 " & i13 & "列目 " & myColumns & IIf(sch = myColumns, " 同じ", " 異なる")
         
        Debug.Print msg
        MsgBox msg
         
        myColumns = WorksheetFunction.Match("%&$", Range(.Cells(3, 1), .Cells(3, rc)), 0)
        MsgBox myColumns
    End With
End Sub

投稿日時: 23/05/08 13:20:25
投稿者: タークン
メールを送信

非常に不思議なことが起こりました。
検索する順番を変更させたら、正しい列番号が取得できたことは報告いたしましたが、
再度、検索する順番を元の順番に戻したところ、
正しい列番号が取得できるようになっていたのです。
 
位置を戻しただけで、コードは一切修正しておりません。
 
一度、検索する位置を離して検索させたところ、
external_product_idと、external_product_id_typeは異なる文字列だぞということを認識した結果、
隣接する位置で検索をかけても、きちんと識別するようになったとしか考えられません。
 
元々、コードに問題は無かったように思えるので、
EXCELLが、文字列の識別方法を学習したという事だったのでしょうか?