Excel (VBA)

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

 
(Windows 10 Pro : Excel 2016)
複数条件の内容が一致したら、セルの数字を書き換える
投稿日時: 23/08/05 22:01:17
投稿者: SHIBARAKU

シート1にキーとなる項目(場所・日付・番号)と変更したい番号を入力します。
シート2に一覧のデータがあります。
シート1のキーを元にシート2の一覧からヒットした対象の行の番号を変更するコードを
下記のとおり記述しましたが、
場所、日付、番号の条件は、セットされているようなのですが、書き換わりません。
ループの書き方に問題があるのでしょうか?
調べられる範囲でいろいろコードを書き換えていたのですが手詰まってしまい、
ご教示のほどよろしくお願いいたします。
 
 
 
Sub 変更貼り付け()
'
'==============================
'予備カード変更
'==============================
    Dim gyo_cnt As Variant
    Dim cellno As Variant
    Dim no_cnt As Variant
    Dim basho_c As Variant
    Dim day_1 As Variant
    Dim no_1 As Variant
    Dim no_2 As Variant
    Dim j As Variant
    Dim cells_cnt As Variant
'
    Sheets("シート1").Select
     
'1行目が空白なら読み飛ばし
       If Workbooks("テスト.xlsm").Sheets("シート1").range("A2").Value = "" Then
             GoTo J1
       Else
             no_cnt = 1
       End If
        
'シート1へ
       Sheets("シート1").Select
'セル範囲を全てループ
    For Each gyo_cnt In range("A2:A6")
       If no_cnt = 1 Then
             cellno = 12
             no_cnt = no_cnt + 1
             no_2 = Workbooks("テスト.xlsm").Sheets("シート1").range("E2").Value
       ElseIf ino_cnt = 2 Then
             cellno = 13
             no_cnt = no_cnt + 1
             no_2 = Workbooks("テスト.xlsm").Sheets("シート1").range("E3").Value
       ElseIf no_cnt = 3 Then
             cellno = 14
             no_cnt = no_cnt + 1
             no_2 = Workbooks("テスト.xlsm").Sheets("シート1").range("E4").Value
       ElseIf no_cnt = 4 Then
             cellno = 15
             no_cnt = no_cnt + 1
             no_2 = Workbooks("テスト.xlsm").Sheets("シート1").range("E5").Value
       ElseIf no_cnt = 5 Then
             cellno = 16
             no_cnt = no_cnt + 1
             no_2 = Workbooks("テスト.xlsm").Sheets("シート1").range("E6").Value
       ElseIf no_cnt >= 6 Then
             GoTo J1
       End If
'検索用_場所コードセット
        basho_c = Workbooks("テスト.xlsm").Sheets("シート1").range("A" & cellno).Value
'検索用_日付セット
        day_1 = Workbooks("テスト.xlsm").Sheets("シート1").range("B" & cellno).Value
'検索用_番号セット
        no_1 = Workbooks("テスト.xlsm").Sheets("シート1").range("C" & cellno).Value
'
'シート2へ
        Sheets("シート2").Select
'
 
           For j = 2 To Cells(Rows.Count, 1).End(xlUp).Row 'シート2の2〜最終行までループ
'
             cells_cnt = 2
             If basho_c = Cells(cells_cnt, 1) And _
                  day_1 = Cells(cells_cnt, 2) And _
                    no_1 = Cells(cells_cnt, 3) Then '場所、日付、番号の条件が揃ったら変更
                        Cells(cells_cnt, 3) = no_2
                        cells_cnt = cells_cnt + 1
             End If
'
           Next
    Next
J1:
End Sub
 
 
 
 
シート1
       A列 B列 C列 D列 E列
行 場所 日付 番号 変更番号
 2 650 20230720 8018 ⇒ 10000
 3 650 20230725 8018 ⇒ 20000
  4 ⇒
  5 ⇒
  6 ⇒                                                                                 
                                                                                                            
                                                                                                            
 
シート2
 
場所    日付     番号
100    20230701    2551
700    20230701    2475
700    20230701    2477
700    20230701    2116
700    20230701    2100
150    20230701    2260
150    20230701    2397
550    20230701    2562
550    20230701    2086
550    20230701    2205
550    20230701    2338
550    20230701    1897
550    20230701    2213
550    20230701    1903
250    20230701    2188
250    20230701    2284
250    20230701    2265
250    20230701    2256
250    20230701    2190
250    20230701    2011
250    20230701    2314
250    20230701    2043
710    20230701    2372
720    20230701    2434
450    20230701    2010
450    20230701    2170
450    20230701    2171
650    20230701    2541
650    20230701    1906
650    20230701    2564
650    20230701    2247
650    20230701    2400
650    20230701    2022
650    20230701    2323
650    20230701    2179
650    20230701    2565
650    20230701    2059
650    20230701    2255
650    20230720    8018 ←ここを[ 10000 ]に変更
650    20230725    8018  ←ここを[ 20000 ]に変更
656    20230701    2356
656    20230701    2521
656    20230701    2385
656    20230701    2302
656    20230701    2135
656    20230701    2236
656    20230701    2134
656    20230701    1668
656    20230701    2195
656    20230701    2033
656    20230701    2303
656    20230701    2301
656    20230701    1973
656    20230720    8018

回答
投稿日時: 23/08/06 12:06:24
投稿者: simple

気づいたことをメモします。
 
(1)

ElseIf ino_cnt = 2 Then
この ino_cnt とは何でしょうか。投稿時のミスでしょうか。
   実行されているコードをそのままコピーペイストすると間違いを防げます。
   実行されているコードがそうなっているのでしょうか。
   コードの最初に
   Option Explicit を入れると、未宣言の変数には警告が出て、こうしたミスを防げます。
   また、変数はすべてをVariant ですまさず、できるだけ内容に沿ったものにしたほうが
   よいでしょう。
(2)
  '検索用_場所コードセット
    basho_c = ws1.Range("A" & cellno).Value
    '検索用_日付セット
    day_1 = ws1.Range("B" & cellno).Value
    '検索用_番号セット
    no_1 = ws1.Range("C" & cellno).Value

    は、cell_noが12〜16ですが、それは説明された表と違いますよね。
    整合性がとれたものにしてください。
(3)
   For j = 2 To Cells(Rows.Count, 1).End(xlUp).Row    'シート2の2〜最終行までループ
        cells_cnt = 2
        If basho_c = Cells(cells_cnt, 1) And _
                day_1 = Cells(cells_cnt, 2) And _
                no_1 = Cells(cells_cnt, 3) Then '場所、日付、番号の条件が揃ったら変更
            Cells(cells_cnt, 3) = no_2
            cells_cnt = cells_cnt + 1
        End If
    Next

    繰り返し変数j が中で使われていないので、各行を見に行っていません。
    何か勘違いがあるのでは?
(4)色々なところに、Workbooks("テスト.xlsm").Sheets("シート1")といったものが
   出てきますが、変数にすると、もっと見やすくなるのではないですか?
(5)デバッグ方法はご存じですか?ステップ実行とか、ローカルウインドウの利用方法とか。
   一発で動作するコードを書けることは稀ですので、デバッグ方法の理解は必須です。
   ご自分でデバッグするのも必要な学習かと思います。

回答
投稿日時: 23/08/06 12:18:19
投稿者: simple

こんな風に書くと良いと思います。
 

Sub 変更貼り付け_改案()
    Dim ws1   As Worksheet
    Dim ws2   As Worksheet
    Dim rng   As Range
    
    Dim basho As String
   'Dim day_1 As Date
    Dim day_1 As String
    Dim no_1  As String
    Dim no_2  As String
   
    Dim j     As Long

    Set ws1 = ThisWorkbook.Sheets("シート1")
    Set ws2 = ThisWorkbook.Sheets("シート2")

    For Each rng In ws1.Range("A2:A6")
        basho = rng.Value               'A列 検索用_場所コード
        day_1 = rng.Offset(, 1).Value   'B列 検索用_日付
        no_1 = rng.Offset(, 2).Value    'C列 検索用_番号
        no_2 = rng.Offset(, 4).Value    'E列 変更後番号

        With ws2
            For j = 2 To .Cells(Rows.Count, 1).End(xlUp).Row    
                If basho = .Cells(j, "A") Then
                    If day_1 = .Cells(j, "B") Then
                        If no_1 = .Cells(j, "C") Then    
                            .Cells(j, "C") = no_2
                         '' .Cells(j, "D") = 1
                        End If
                    End If
                End If
            Next
        End With
    Next
End Sub

【備考】
If basho = .Cells(j, "A") And _
     day_1 = .Cells(j, "B") And _
      no_1 = .Cells(j, "C") Then
と書いても同じ結果は得られますが、
こう書くと、basho が Cells(j, "A")と不一致でも、
     day_1 = .Cells(j, "B") や
      no_1 = .Cells(j, "C") を
評価してしまうので、無駄です。
上記のコードのようにIFを重ねたほうが実行効率は良くなります。

回答
投稿日時: 23/08/06 16:44:07
投稿者: WinArrow

シート2側のループをなくしたサンプルコードを紹介します。
シート2側の検索には、オートフィルタを使用しています。
3つの検索項目が1件という制限を付けています。
参考にしてください。
 

Sub 別案サンプル()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim RX1 As Long
Dim CNT As Long

    Set ws1 = Sheets("Sheet1")
    Set ws2 = Sheets("sheet2")
    
    With ws1
        For RX1 = 2 To .Cells(.Rows.Count, "A").End(xlUp).Row
            If WorksheetFunction.CountIfs( _
                ws2.Columns("A"), .Cells(RX1, "B"), _
                ws2.Columns("B"), .Cells(RX1, "C"), _
                ws2.Columns("C"), .Cells(RX1, "D")) = 1 Then _

                Call WS2UPDaTE(ws2:=ws2, _
                        key1:=.Cells(RX1, "B"), _
                        key2:=.Cells(RX1, "C"), _
                        key3:=.Cells(RX1, "D"), _
                        DATA:=.Cells(RX1, "E"))
            End If
        Next
    End With


    
End Sub

Private Sub WS2UPDaTE(ws2, key1, key2, key3, DATA)
Dim MYCELL As Range
    With ws2
        With .Range("A1")
            .AutoFilter
            .AutoFilter field:=1, Criteria1:=key1
            .AutoFilter field:=2, Criteria1:=key2
            .AutoFilter field:=3, Criteria1:=key3
            For Each MYCELL In .CurrentRegion.SpecialCells(xlCellTypeVisible)
                If MYCELL.Column = 3 Then
                    MYCELL.Value = DATA
                End If
            Next
            .AutoFilter
        End With
    End With
    
End Sub

投稿日時: 23/08/07 14:06:41
投稿者: SHIBARAKU

simpleさん
WinArrowさん
 
質問のコードが間違っていながら適切な説明を頂き、ありがとうございました。
いくつか同じようなコードを使用するEXCELを作成する為、両方を試したいと思います。