Excel (VBA)

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

 
(Windows 10全般 : Microsoft 365)
数式を入力(関数組み合わせ)
投稿日時: 23/08/18 14:59:32
投稿者: wa-nn

こんにちは。VBA初心者です。
IFNA×INDEX×MACTHを組み合わせをした数式を入力したいです。
INDEX×MACTHでは入力できたのですが、IFNAを追加したら”型が一致しません”とエラーになり、
WorksheetFunctionでは構文エラーになります。
 
それぞれ原因と、対処法を教えて頂けると幸いです。
お手数お掛けしますが、宜しくお願い致します。
 
下記

Dim plan_lastRow As Long
  plan_lastRow = Cells(Rows.Count, "E").End(xlUp).Row
  Range("E5:E" & plan_lastRow).Formula = "=INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0))"
   Range("E5:E" & plan_lastRow).Formula = "=IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0))," - ")"
  Range("E5:E" & plan_lastRow) = WorksheetFunction.IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0))," - ")

回答
投稿日時: 23/08/18 15:20:35
投稿者: taitani
投稿者のウェブサイトに移動

Range("E5:E" & plan_lastRow).Formula = "=IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0))," - ")"
 
これを、
 
Range("E5:E" & plan_lastRow).Formula = "=IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0)),"" - "")"
 
とすることで、"型が一致しません" エラーは回避可能だと思います。
 
同じように、
 
Range("E5:E" & plan_lastRow) = WorksheetFunction.IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0))," - ")
 
も修正してみましょう。

投稿日時: 23/08/18 15:53:35
投稿者: wa-nn

taitani さんの引用:
Range("E5:E" & plan_lastRow).Formula = "=IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0))," - ")"
 
これを、
 
Range("E5:E" & plan_lastRow).Formula = "=IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0)),"" - "")"
 
とすることで、"型が一致しません" エラーは回避可能だと思います。
 
同じように、
 
Range("E5:E" & plan_lastRow) = WorksheetFunction.IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0))," - ")
 
も修正してみましょう。

 
ありがとうございます。
こちらは回避できました!!!
Range("E5:E" & plan_lastRow).Formula = "=IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0)),"" - "")"

 
下記が構文エラーになります。。。。
御確認頂けると幸いです。
Range("E5:E" & plan_lastRow) = WorksheetFunction.IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0)),"" - "")

回答
投稿日時: 23/08/18 16:27:45
投稿者: taitani
投稿者のウェブサイトに移動

うーん、計算結果を範囲に一気に貼り付けようとしているので、エラーになる見解です。
一度、計算式「Range("E5:E" & plan_lastRow).Formula = "=IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0)),"" - "")"」を入れて、
 
Range("E5:E" & plan_lastRow).value=Range("E5:E" & plan_lastRow).value
 
で、値にするとか。

回答
投稿日時: 23/08/18 16:49:56
投稿者: sk

引用:
WorksheetFunction.IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0))," - ")

(標準モジュール)
------------------------------------------------------------------
Sub TestMacro1()
 
    Dim ws1 As Worksheet
    Dim ws2 As Worksheet
     
    Set ws1 = Worksheets("指示書")
    Set ws2 = ActiveSheet 'できればワークシートを明示的に指定した方がよい
     
    Dim lngFirstRow As Long
    Dim lngLastRow As Long
     
    With ws2
        lngFirstRow = 5
        lngLastRow = .Cells(.Rows.Count, "E").End(xlUp).Row
        If lngFirstRow <= lngLastRow Then
            .Range("E" & lngFirstRow & ":" & "E" & lngLastRow).ClearContents
        End If
    End With
     
    Dim lngRow As Long
    Dim varReturnValue As Variant
    Dim strErrMsg As String
     
    For lngRow = lngFirstRow To lngLastRow
         
        varReturnValue = Empty
         
        On Error Resume Next
        varReturnValue = WorksheetFunction.Match(ws2.Cells(lngRow, "D"), ws1.Range("$G:$G"), 0)
         
        Select Case Err.Number
            Case 0
                varReturnValue = WorksheetFunction.Index(ws1.Range("I:I"), varReturnValue)
            Case 1004
                Err.Clear
                varReturnValue = " - "
            Case Else
                strErrMsg = lngRow & " 行目の参照中に以下の実行時エラーが発生しました。" & vbCrLf & vbCrLf & _
                            Err.Number & ": " & Err.Description
                MsgBox strErrMsg, _
                       vbCritical, _
                       "実行時エラー"
                Set ws2 = Nothing
                Set ws1 = Nothing
                Exit Sub
        End Select
        On Error GoTo 0
             
        ws2.Cells(lngRow, "E").Value = varReturnValue
     
    Next
     
    Set ws2 = Nothing
    Set ws1 = Nothing
     
End Sub
------------------------------------------------------------------
 
WorksheetFunction オブジェクトのメソッドとして呼び出すならば
以上のような形になるでしょう。
 
この場合、WorksheetFunction.IfNa メソッドを呼び出しても
全く意味がありません。

回答
投稿日時: 23/08/18 16:55:19
投稿者: Suzu

まず、右辺の組立方がまずいです。
 
 
INDEX関数 は、 VBA内にはありません。
これも、WorkSheetFuction.INDEX としなければなりません。 Matchも同様
(無い訳では無いが、ワークシート関数とは、動作が違います)
 
詳しくは
【EXCEL小ネタ】EXCELのMATCH関数は実は2つある?
https://infoxnet.co.jp/ftblog/index.php/2022/04/15/story519e104471364a5d/
をどうそ。
 
それぞれ、WorkSheetFunctionをつけて
Range("E5:E" & plan_lastRow) = WorksheetFunction.IFNA(WorksheetFunctionINDEX(指示書!I:I,WorkSheetFunctiion.MATCH($D5,指示書!$G:$G,0))," - ")
 
こうしても、
 
 
コンパイルエラー
修正候補 区切り記号 または)
になるはずです。
 
I:I の位置の 「:」がマークされます。
 
VBA の中では、: は別の意味になるので、使えません と言っています。
 
セル範囲を参照して欲しいので Rangeを使って指定する必要があります。
また、別のWorkSheetのセルを参照しなければならない
 
 
むりやりやるとすれば
 
Range("E5:E" & plan_lastRow) = WorksheetFunction.IfNa(WorksheetFunctionINDEX(Worksheets("指示書").Range("I:I"), WorkSheetFunctoion.Match(Range("D5"), Worksheets("指示書").Range("G:G"), 0)), " - ")
 
 
ですが・・・
 
 
右辺で返すのは計算結果。つまり、一意の値になります。
 
対し、左辺は、セル範囲 を指定しています。
 
セル範囲に 一意の値を 代入してもしょうがないですよね。
 
 
ないので、意味のない事をやらせようとしていますので、今回はこの書き方は諦めましょう。
 
 
 
回避する方法が無い訳ではありませんが、
もうちょっとスキルアップしてからの話になるでしょうから
ここでは、お話しません。

回答
投稿日時: 23/08/18 17:02:27
投稿者: sk

sk さんの引用:

    With ws2
        lngFirstRow = 5
        lngLastRow = .Cells(.Rows.Count, "E").End(xlUp).Row
        If lngFirstRow <= lngLastRow Then
            .Range("E" & lngFirstRow & ":" & "E" & lngLastRow).ClearContents
        End If
    End With

このブロックに関しては、以下のステートメントを挿入しておいた方がよさげ。
 
----------------------------------------------------------------
 
    With ws2
        lngFirstRow = 5
        lngLastRow = .Cells(.Rows.Count, "E").End(xlUp).Row
        If lngFirstRow <= lngLastRow Then
            .Range("E" & lngFirstRow & ":" & "E" & lngLastRow).ClearContents
        End If
        lngLastRow = .Cells(.Rows.Count, "D").End(xlUp).Row
    End With
 
----------------------------------------------------------------

回答
投稿日時: 23/08/18 17:02:30
投稿者: simple

    With Application
        Range("E5:E" & plan_lastRow) = _
          .IfNa(.Index(Sheets(2).Columns("I"), _
                       .Match(Range("D5:D" & plan_lastRow), Sheets(2).Columns("G"), 0) _
                ), _
               " - ")
    End With
などと書けないことは無いと思いますが、
taitaniさんご指摘のとおり、二番目の方法で.Value = .Valueとするのが簡便でしょう。
 
ちなみに、Excel365だと、もっと便利なワークシート関数があるのではないかと思います。
(よく知りませんが)

投稿日時: 23/08/18 18:16:42
投稿者: wa-nn

taitani さんの引用:
うーん、計算結果を範囲に一気に貼り付けようとしているので、エラーになる見解です。
一度、計算式「Range("E5:E" & plan_lastRow).Formula = "=IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0)),"" - "")"」を入れて、
 
Range("E5:E" & plan_lastRow).value=Range("E5:E" & plan_lastRow).value
 
で、値にするとか。

 
一気に範囲は指定できないのですね。。。
値張りだと困るので、検討します。
ありがとうございますm(_ _)m

投稿日時: 23/08/18 18:29:26
投稿者: wa-nn

sk さんの引用:
引用:
WorksheetFunction.IFNA(INDEX(指示書!I:I,MATCH($D5,指示書!$G:$G,0))," - ")

(標準モジュール)
------------------------------------------------------------------
Sub TestMacro1()
 
    Dim ws1 As Worksheet
    Dim ws2 As Worksheet
     
    Set ws1 = Worksheets("指示書")
    Set ws2 = ActiveSheet 'できればワークシートを明示的に指定した方がよい
     
    Dim lngFirstRow As Long
    Dim lngLastRow As Long
     
    With ws2
        lngFirstRow = 5
        lngLastRow = .Cells(.Rows.Count, "E").End(xlUp).Row
        If lngFirstRow <= lngLastRow Then
            .Range("E" & lngFirstRow & ":" & "E" & lngLastRow).ClearContents
        End If
    End With
     
    Dim lngRow As Long
    Dim varReturnValue As Variant
    Dim strErrMsg As String
     
    For lngRow = lngFirstRow To lngLastRow
         
        varReturnValue = Empty
         
        On Error Resume Next
        varReturnValue = WorksheetFunction.Match(ws2.Cells(lngRow, "D"), ws1.Range("$G:$G"), 0)
         
        Select Case Err.Number
            Case 0
                varReturnValue = WorksheetFunction.Index(ws1.Range("I:I"), varReturnValue)
            Case 1004
                Err.Clear
                varReturnValue = " - "
            Case Else
                strErrMsg = lngRow & " 行目の参照中に以下の実行時エラーが発生しました。" & vbCrLf & vbCrLf & _
                            Err.Number & ": " & Err.Description
                MsgBox strErrMsg, _
                       vbCritical, _
                       "実行時エラー"
                Set ws2 = Nothing
                Set ws1 = Nothing
                Exit Sub
        End Select
        On Error GoTo 0
             
        ws2.Cells(lngRow, "E").Value = varReturnValue
     
    Next
     
    Set ws2 = Nothing
    Set ws1 = Nothing
     
End Sub
------------------------------------------------------------------
 
WorksheetFunction オブジェクトのメソッドとして呼び出すならば
以上のような形になるでしょう。
 
この場合、WorksheetFunction.IfNa メソッドを呼び出しても
全く意味がありません。

 
ありがとうございます。上記コードでできました。
WorksheetFunctionを使うと、
複数範囲ではなく単一セル、IfNaの代わりにOn Errorで対処しないといけないのですね(汗)