Сопоставление значений диапазона с именами листов, затем поиск ячейки и копирование значения рядом с ней

#excel #vba

#excel #vba

Вопрос:

У меня есть два листа

  1. Источник (ThisWorkbook) — содержит несколько листов
  2. Назначение (WBD) — содержит 1 лист

Это процесс:

  1. Сравните каждую ячейку из диапазона в WBD (B2: B6) со всеми именами листов в этой рабочей книге
  2. Если найдено совпадение, выберите диапазон в WBD (C2: C7) и найдите его на соответствующем листе
  3. (вот тут у меня проблемы) Как мне получить значение ячейки средней цены? Нужен ли мне еще один цикл?

* расстояние между типом и ценой соответствует.

Вот что я получил до сих пор:

 For Each cel In WBD.Worksheets(1).Range("B2:B6")
    For Each ws In ThisWorkbook.Worksheets
        ws.Activate
            If ws.Name = cel.Value Then
                'find C2:C7 , offset, copy avg price, paste
    Next ws
Next cel
 

Источник — ThisWorkbook

Источник - ThisWorkbook

Назначение — WBD

Назначение - WBD

Ответ №1:

Поиск по листам

Подход Application.Match

 Option Explicit

Sub lookupValues()

    Const dFirst As Long = 2
    Const sFirst As Long = 2
    
    Dim swb As Workbook: Set swb = ThisWorkbook
    'Dim WBD As Workbook: Set WBD = ThisWorkbook
    
    Dim drg As Range
    Dim dLast As Long
    With WBD.Worksheets(1)
        dLast = .Cells(.Rows.Count, "C").End(xlUp).Row ' because merged in 'B'
        Set drg = .Cells(dFirst, "B").Resize(dLast - dFirst   1)
    End With
    
    Dim src As Worksheet
    Dim srg As Range
    Dim cel As Range
    Dim dMatch As Variant
    Dim sMatch As Variant
    Dim sLast As Long
    
    For Each src In swb.Worksheets
        sLast = src.Cells(src.Rows.Count, "C").End(xlUp).Row
        Set srg = Nothing
        On Error Resume Next
        Set srg = src.Cells(sFirst, "B").Resize(sLast - sFirst   1)
        On Error GoTo 0
        If Not srg Is Nothing Then
            dMatch = Application.Match(src.Name, drg, 0)
            If IsNumeric(dMatch) Then
                Set cel = drg.Cells(dMatch)
                Do
                    sMatch = Application.Match(cel.Offset(, 1).Value, srg, 0)
                    If IsNumeric(sMatch) Then
                        cel.Offset(, 2).Value _
                            = srg.Cells(sMatch).Offset(3, 2).Value
                    End If
                    Set cel = cel.Offset(, 1).Offset(1, -1) ' because merged
                Loop Until Len(cel.Value) > 0 Or cel.Row > dLast
            End If
        End If
    Next src
    
    'WBD.Save
    'swb.Close SaveChanges:=False
    
End Sub
 

Комментарии:

1. Я пытаюсь понять, что делает каждая строка. Можете ли вы просветить меня по With WBD.Worksheets(1) dLast = .Cells(.Rows.Count, "C").End(xlUp).Row ' because merged in 'B' Set drg = .Cells(dFirst, "B").Resize(dLast - dFirst 1) End With

2. Сначала вычисляется последняя строка в столбце C , потому что в столбце B результат может быть неправильным из-за объединенных ячеек. Затем он определяет столбец Destination (Read) Column Range in B , используя в качестве первой строки константу dFirst , а для последней строки только что вычисленную dLast (на вашем изображении B2:B7 ; вычисленная последняя строка в столбце B приведет к B2:B6 (неправильному)).

3. Resize Часть немного сложнее. У вас есть .Cells(dFirst, "B") то же .Range("B" amp; dFirst) самое, что и или в данном конкретном случае B2 . Представьте, что вычисленная последняя строка была row 7 . Если вы это сделаете Range("B2").Resize(7 - 2 1) , вы можете упростить Range("B2").Resize(6) , что в итоге Range("B2:B7") (нет Range("B2:B8") ). Обратите внимание, что Range("A1").Resize(1) это все еще Range("A1") и Range("A1").Resize(2) есть Range("A1:A2") , пока Range("A1").Offset(1) есть Range("A2") .

4. Не могли бы вы помочь мне изменить код, если строка / столбцы настроены таким образом? imgur.com/a/khG6oNA

Ответ №2:

 Sub m1()
    For Each cel In ThisWorkbook.Worksheets(1).Range("B2:B6")
        If cel.MergeCells Then  
            shname = cel.MergeArea.Cells(1, 1).Value    ' if cells merged, only first cell contains value
        Else
            shname = cel.Value
        End If
        For Each ws In ThisWorkbook.Worksheets
            If ws.Name = shname Then
                Set f = ws.Columns("B").Find(cel.Offset(0, 1).Value, lookat:=xlWhole)
                If Not f Is Nothing Then ' its found
                    Set f = ws.Cells.Find("avg price", after:=f.Offset(0, 1))
                    If Not f Is Nothing Then ' its found
                        cel.Offset(0, 2).Value = f.Offset(0, 1).Value
                    End If
                End If
            End If
        Next ws
    Next cel
End Sub
 

Комментарии:

1. Я забыл упомянуть, что средняя цена указана в одном типе данных. Я пытаюсь выяснить, почему код не работает с моей стороны.

2. Тип данных в этом случае не имеет значения, поскольку команда cel. Смещение (0, 2) .Значение = f.Смещение (0, 1) .Значение присваивает ячейке слева значение любого типа из ячейки справа. Что касается причин неработоспособности этого кода, это обычно решается путем пошаговой отладки кода

3. Нужно ли объявлять f?

4. Переменные в VBA не обязательно объявлять, без объявления они имеют тип Variant . Необходимость объявления переменных зависит от того, есть ли в модуле явный оператор Option.

5. Я думаю, что я получил свою ошибку, значение, которое я нахожу в B, является объединенной ячейкой. Кроме того, ячейка средней цены и ячейка справа от нее также являются объединенной ячейкой. Как мне это решить?