Excel VBA, проблема с диапазоном массива

У меня есть приведенный ниже код, который на основе пользовательского ввода в ячейке B5 на рабочем листе «Основной» будет искать номер входной части еще на двух листах, «НЕДОСТАТОК» и «PPN», и возвращать соответствующие столбцы и строки данных, код работает но мне нужно изменить диапазон данных для массива limitedData со столбцов B на F, на A на F, плюс L и N. Я исследовал и попробовал несколько методов, таких как диапазон объединения Union(promptSheet.Range("A1:F" & promptLastRow), promptSheet.Range("L1:L" & promptLastRow), promptSheet.Range("N1:N" & promptLastRow)).Value и promptData = promptSheet.Range("A1:F" & promptLastRow & ", L1:L" & promptLastRow & ", N1:N" & promptLastRow).Value, но ни один из них не работает, это возвращает правильные значения для A:F, но для следующих двух столбцов L и N возвращает все #ССЫЛКА! ценности. Пробовал использовать Кто-нибудь может помочь в этом? Буду признателен за любую оказанную помощь! Это связано с несмежным диапазоном?

Sub Button2_Click()
Dim partNum As String
Dim mainSheet As Worksheet
Dim shortageSheet As Worksheet
Dim ppnSheet As Worksheet
Dim mainLastRow As Long
Dim shortageLastRow As Long
Dim ppnLastRow As Long
Dim shortageData As Variant
Dim ppnData As Variant
Dim i As Long
Dim recordFound As Boolean
Application.ScreenUpdating = False
Set mainSheet = ThisWorkbook.Sheets("Main")
Set shortageSheet = ThisWorkbook.Sheets("SHORTAGE")
Set ppnSheet = ThisWorkbook.Sheets("PPN")
partNum = mainSheet.Range("B5").Value
If partNum = "" Then
    MsgBox "Please enter a part number.", vbExclamation
    Exit Sub
End If
mainSheet.Range("B11:F" & mainSheet.Cells(mainSheet.Rows.Count, "B").End(xlDown).Row).ClearContents
mainSheet.Range("I11:O" & mainSheet.Cells(mainSheet.Rows.Count, "I").End(xlDown).Row).ClearContents
shortageLastRow = shortageSheet.Cells(shortageSheet.Rows.Count, "B").End(xlUp).Row
shortageData = shortageSheet.Range("B1:F" & shortageLastRow).Value
For i = 1 To shortageLastRow
    If shortageData(i, 1) = partNum Then
        mainLastRow = mainSheet.Cells(mainSheet.Rows.Count, "B").End(xlUp).Row + 1
        mainSheet.Range("B" & mainLastRow & ":I" & mainLastRow).Value = _
            Application.Index(shortageData, i, Array(1, 2, 3, 4, 5))
        recordFound = True
    End If
Next i
If Not recordFound Then
    MsgBox "No records found in SHORTAGE"
End If
recordFound = False
ppnLastRow = ppnSheet.Cells(ppnSheet.Rows.Count, "G").End(xlUp).Row
ppnData = ppnSheet.Range("G1:N" & ppnLastRow).Value
For i = 1 To ppnLastRow
    If ppnData(i, 1) = partNum Then
        mainLastRow = mainSheet.Cells(mainSheet.Rows.Count, "I").End(xlUp).Row + 1
        mainSheet.Range("I" & mainLastRow & ":O" & mainLastRow).Value = _
            Application.Index(ppnData, i, Array(1, 2, 3, 4, 5, 6, 7, 8))
        recordFound = True
    End If
Next i
If Not recordFound Then
    MsgBox "No records found in PPN"
End If
Application.CutCopyMode = False
Application.ScreenUpdating = True
MsgBox "Search complete!", vbInformation
End Sub

Каков ожидаемый результат для функции Application.Index?

Black cat 28.05.2023 14:47
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
1
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Эта функция довольно длинная и сложная, поэтому я бы начал с ее рефакторинга. Прежде всего, вы должны извлечь две функции, подобные этой:

Option Explicit

Public Sub Button2_Click()
    Application.ScreenUpdating = False
    
    Dim mainSheet As Worksheet: Set mainSheet = ThisWorkbook.Sheets("Main")
    mainSheet.Range("B11:F" & mainSheet.Cells(mainSheet.Rows.Count, "B").End(xlDown).Row).ClearContents
    mainSheet.Range("I11:O" & mainSheet.Cells(mainSheet.Rows.Count, "I").End(xlDown).Row).ClearContents
    Dim partNum As String: partNum = mainSheet.Range("B5").Value
    If partNum = "" Then
        MsgBox "Please enter a part number.", vbExclamation
        Exit Sub
    End If
    
    SearchShortage mainSheet, partNum
    
    SearchPpn mainSheet, partNum
    
    Application.CutCopyMode = False
    Application.ScreenUpdating = True
    MsgBox "Search complete!", vbInformation
End Sub

Public Sub SearchShortage(mainSheet As Worksheet, partNum As String)
    Dim shortageSheet As Worksheet: Set shortageSheet = ThisWorkbook.Sheets("SHORTAGE")
    Dim shortageLastRow As Long: shortageLastRow = shortageSheet.Cells(shortageSheet.Rows.Count, "B").End(xlUp).Row
    Dim shortageData As Variant: shortageData = shortageSheet.Range("B1:F" & shortageLastRow).Value
    Dim recordFound As Boolean: recordFound = False
    Dim i As Long: For i = 1 To shortageLastRow
        If shortageData(i, 1).Value = partNum Then
            Dim mainLastRow As Long: mainLastRow = mainSheet.Cells(mainSheet.Rows.Count, "B").End(xlUp).Row + 1
            mainSheet.Range("B" & mainLastRow & ":I" & mainLastRow).Value = _
                WorksheetFunction.Index(shortageData, i, Array(1, 2, 3, 4, 5))
            recordFound = True
        End If
    Next i
    If Not recordFound Then
        MsgBox "No records found in SHORTAGE"
    End If
End Sub

Public Sub SearchPpn(mainSheet As Worksheet, partNum As String)
    Dim ppnSheet As Worksheet: Set ppnSheet = ThisWorkbook.Sheets("PPN")
    Dim ppnLastRow As Long: ppnLastRow = ppnSheet.Cells(ppnSheet.Rows.Count, "G").End(xlUp).Row
    Dim ppnData As Variant: ppnData = ppnSheet.Range("G1:N" & ppnLastRow).Value
    Dim recordFound As Boolean: recordFound = False
    Dim i As Long: For i = 1 To ppnLastRow
        If ppnData(i, 1).Value = partNum Then
            Dim mainLastRow As Long: mainLastRow = mainSheet.Cells(mainSheet.Rows.Count, "I").End(xlUp).Row + 1
            mainSheet.Range("I" & mainLastRow & ":O" & mainLastRow).Value = _
                WorksheetFunction.Index(ppnData, i, Array(1, 2, 3, 4, 5, 6, 7, 8))
            recordFound = True
        End If
    Next i
    If Not recordFound Then
        MsgBox "No records found in PPN"
    End If
End Sub

Затем я бы продолжил поиск сходства между SearchShortage и SearchPpn и создал более абстрактную функцию, которая вызывается с другими параметрами. Однако, поскольку у меня нет вашей рабочей книги, я не могу протестировать какие-либо модификации. И я вижу некоторые несоответствия, которые могут вызвать ошибку (например, диапазон B:I mainSheet (8 столбцов) перезаписывается 5 значениями, а его диапазон I:O (7 столбцов) перезаписывается 8 значениями). Так что я пропущу эту часть.

Далее, я хотел бы точно понять вашу проблему. Основываясь на том, что вы написали, я думаю, вы хотели бы добавить функцию, назовем ее SearchPrompt, которая имеет аналогичную задачу, например:

Public Sub Searchprompt(mainSheet As Worksheet, partNum As String)
    Dim promptSheet As Worksheet: Set promptSheet = ThisWorkbook.Sheets("PROMPT")
    Dim promptLastRow As Long: promptLastRow = promptSheet.Cells(promptSheet.Rows.Count, "B").End(xlUp).Row
    Dim promptData As Variant: promptData = Union(promptSheet.Range("A1:F" & promptLastRow), promptSheet.Range("L1:L" & promptLastRow), promptSheet.Range("N1:N" & promptLastRow)).Value,
    Dim recordFound As Boolean: recordFound = False
    Dim i As Long: For i = 1 To promptLastRow
        If promptData(i, 1).Value = partNum Then
            Dim mainLastRow As Long: mainLastRow = mainSheet.Cells(mainSheet.Rows.Count, "S").End(xlUp).Row + 1
            mainSheet.Range("S" & mainLastRow & ":Z" & mainLastRow).Value = _
                WorksheetFunction.Index(promptData, i, Array(1, 2, 3, 4, 5, 6, 7, 8))
            recordFound = True
        End If
    Next i
    If Not recordFound Then
        MsgBox "No records found in prompt"
    End If
End Sub

И проблема в том, что первые шесть ячеек (в приведенном выше примере, S:X, как я догадался, что B:F — это дефицит, затем 2 пустых столбца, I:P для PPN, затем 2 пустых столбца и, наконец, S: Z для подсказки) заполнены правильными значениями, а последние два (Y: Z) заполнены #REF!.

Вы уже правильно заметили, что это может быть вызвано несмежным диапазоном. Я предполагаю, что это так, Union создает объект Range, который имеет несколько «поддиапазонов» в своем свойстве .Areas, и если вы ссылаетесь на его .Value, то он интерпретируется как .Areas(1).Value, а остальное (например, .Areas(2) игнорируется).

Теперь есть два решения:

(1) Повторите эти .Areas в вашем коде - это немного сложнее, чем другое решение, и я недостаточно знаю ваш рабочий лист, чтобы сделать хорошее предположение об этом.

(2) Просто используйте непрерывный диапазон. Вы можете искать в диапазоне A:N, а затем позже (при представлении результатов) опустить ненужные вам ячейки. Вы можете сделать это, настроив числа в массиве, указанном в качестве третьего параметра Application.Index (точнее, WorksheetFunction.Index), например так:

Public Sub Searchprompt(mainSheet As Worksheet, partNum As String)
    Dim promptSheet As Worksheet: Set promptSheet = ThisWorkbook.Sheets("PROMPT")
    Dim promptLastRow As Long: promptLastRow = promptSheet.Cells(promptSheet.Rows.Count, "B").End(xlUp).Row
    Dim promptData As Variant: promptData = promptSheet.Range("A1:N" & promptLastRow).Value
    Dim recordFound As Boolean: recordFound = False
    Dim i As Long: For i = 1 To promptLastRow
        If promptData(i, 1).Value = partNum Then
            Dim mainLastRow As Long: mainLastRow = mainSheet.Cells(mainSheet.Rows.Count, "S").End(xlUp).Row + 1
            mainSheet.Range("S" & mainLastRow & ":X" & mainLastRow).Value = _
                WorksheetFunction.Index(promptData, i, Array(1, 2, 3, 4, 5, 6, 12, 14))
            recordFound = True
        End If
    Next i
    If Not recordFound Then
        MsgBox "No records found in prompt"
    End If
End Sub

Обратите внимание, что WorksheetFunction.Index вызывается с помощью Array(1, 2, 3, 4, 5, 6, 12, 14): 1 .. 6 относятся к A .. F, 12 к L и 14 к N.

Другие вопросы по теме