Excel/VBA 匹配 2 个条件,提取序列中的最后一个匹配项和中断序列后的第一个匹配项
Excel/VBA to match 2 criteria, extracting last match in sequence and first match after broken sequence
我开始使用 VBA 编程,并且对如何从非顺序数据中提取我需要的内容感到困惑。
我尝试使用 excel 函数,例如 "VLookup"、"INDEX(Match("、"MAX(If"、"MIN(If",但只能找到第一个或最后一个匹配项,而在序列所在的位置周围找不到任何东西休息。我不认为使用 Excel 函数是可能的,这就是为什么我试图弄清楚如何在 VBA 中做到这一点。也许 "If, Else, Loop" 但不确定。
条件:必须具有匹配的 "Item desc" 和 "Supplier"。
输出 1:在交付缺口之后找到 Year/Week。
输出 2:在交付缺口之前找到 Year/Week。
下面是 Excel 工作表 1 上的原始数据布局和工作表 2 上的分析的示例图像。
Image of Excel issue:
这段代码应该可以满足您的要求,但请检查它是否没有出错。
我没有检查太多,所以它可能会产生错误。
运行 它在工作簿的副本中。
你应该将它放入 class 模块并命名为 'CItem':
Public pItemDescription As String
Public pSupplier As String
Public pDateDelivery As Collection
https://excelmacromastery.com/vba-class-modules/
'Analysis' 中的 table 应该是空的。
然后进入常规模块:
Option Explicit
Sub SortCheck()
Dim aSht As Worksheet
Dim bSht As Worksheet
Dim tempItemDescription As String
Dim tempSupplier As String
Dim tempDateDelivery As String
Dim xItemsAll As Collection
Dim xItem As CItem
Dim xI As Variant
Dim flag As Boolean
Dim xTemp As Variant
Dim i As Long
Dim j As Long
Dim k As Long
Dim Row As Long
Set xItemsAll = New Collection
Set xItem = New CItem
Set aSht = Worksheets("Raw Data")
Set bSht = Worksheets("Analysis")
Row = 2
flag = True
Do
' If the cell is empty, stop populating the collection
If aSht.Cells(Row, 2).Value = "" Then Exit Do
' ---
tempDateDelivery = aSht.Cells(Row, 1).Value
tempItemDescription = aSht.Cells(Row, 2).Value
tempSupplier = aSht.Cells(Row, 3).Value
'If xItemsAll contains some records, check wheter similar records exist
If xItemsAll.Count > 0 Then
For Each xI In xItemsAll
If tempItemDescription = xI.pItemDescription And tempSupplier = xI.pSupplier Then
Set xItem = New CItem
Set xItem = xI
xItem.pDateDelivery.Add tempDateDelivery
Set xItem = Nothing
flag = False
Exit For
Else
flag = True
End If
Next xI
End If
' If the first pass or no element in collection yet, create new record
If flag = True Then
Set xItem = New CItem
With xItem
.pItemDescription = tempItemDescription
.pSupplier = tempSupplier
Set .pDateDelivery = New Collection
.pDateDelivery.Add tempDateDelivery
End With
xItemsAll.Add xItem
Set xItem = Nothing
flag = False
End If
Row = Row + 1
Loop
'Sort the collection - Item Description in order
For i = 1 To xItemsAll.Count - 1
For j = i + 1 To xItemsAll.Count
If xItemsAll(i).pItemDescription > xItemsAll(j).pItemDescription Then
Set xItem = New CItem
Set xItem = xItemsAll(j)
xItemsAll.Remove j
If j <> xItemsAll.Count + 1 Then
xItemsAll.Add xItemsAll(i), , j
Else
xItemsAll.Add xItemsAll(i), , , j - 1
End If
xItemsAll.Remove i
If i <> xItemsAll.Count + 1 Then
xItemsAll.Add xItem, , i
Else
xItemsAll.Add xItem, , , i - 1
End If
Set xItem = Nothing
End If
Next j
Next i
'Sort the collection - Suplier in order
For i = 1 To xItemsAll.Count - 1
For j = i + 1 To xItemsAll.Count
If xItemsAll(i).pItemDescription = xItemsAll(j).pItemDescription Then
If xItemsAll(i).pSupplier > xItemsAll(j).pSupplier Then
Set xItem = New CItem
Set xItem = xItemsAll(j)
xItemsAll.Remove j
If j <> xItemsAll.Count + 1 Then
xItemsAll.Add xItemsAll(i), , j
Else
xItemsAll.Add xItemsAll(i), , , j - 1
End If
xItemsAll.Remove i
If i <> xItemsAll.Count + 1 Then
xItemsAll.Add xItem, , i
Else
xItemsAll.Add xItem, , , i - 1
End If
Set xItem = Nothing
End If
End If
Next j
Next i
'Sort the collection - Dates in order
For k = 1 To xItemsAll.Count
For i = 1 To xItemsAll(k).pDateDelivery.Count - 1
For j = i + 1 To xItemsAll(k).pDateDelivery.Count
If xItemsAll(k).pItemDescription = xItemsAll(k).pItemDescription Then
If xItemsAll(k).pSupplier = xItemsAll(k).pSupplier Then
If xItemsAll(k).pDateDelivery(i) > xItemsAll(k).pDateDelivery(j) Then
xTemp = xItemsAll(k).pDateDelivery(j)
xItemsAll(k).pDateDelivery.Remove j
If j <> xItemsAll(k).pDateDelivery.Count + 1 Then
xItemsAll(k).pDateDelivery.Add xItemsAll(k).pDateDelivery(i), , j
Else
xItemsAll(k).pDateDelivery.Add xItemsAll(k).pDateDelivery(i), , , j - 1
End If
xItemsAll(k).pDateDelivery.Remove i
If i <> xItemsAll(k).pDateDelivery.Count + 1 Then
xItemsAll(k).pDateDelivery.Add xTemp, , i
Else
xItemsAll(k).pDateDelivery.Add xTemp, , , i - 1
End If
End If
End If
End If
Next j
Next i
Next k
Row = 2
For i = 1 To xItemsAll.Count
For j = 1 To xItemsAll(i).pDateDelivery.Count - 1
If CLng(Mid(xItemsAll(i).pDateDelivery(j + 1), 5)) <> (CLng(Mid(xItemsAll(i).pDateDelivery(j), 5)) + 1) Then
bSht.Cells(Row, 1).Value = xItemsAll(i).pDateDelivery(j + 1)
bSht.Cells(Row, 2).Value = xItemsAll(i).pDateDelivery(j)
bSht.Cells(Row, 3).Value = xItemsAll(i).pItemDescription
bSht.Cells(Row, 4).Value = xItemsAll(i).pSupplier
Row = Row + 1
End If
Next j
Next i
End Sub
要使代码正常工作,它必须是 201801、201805 等,而不是 20181、20185 等。因此,如果您有不同的代码,则必须使用函数或 vba 修改它。
我开始使用 VBA 编程,并且对如何从非顺序数据中提取我需要的内容感到困惑。 我尝试使用 excel 函数,例如 "VLookup"、"INDEX(Match("、"MAX(If"、"MIN(If",但只能找到第一个或最后一个匹配项,而在序列所在的位置周围找不到任何东西休息。我不认为使用 Excel 函数是可能的,这就是为什么我试图弄清楚如何在 VBA 中做到这一点。也许 "If, Else, Loop" 但不确定。
条件:必须具有匹配的 "Item desc" 和 "Supplier"。
输出 1:在交付缺口之后找到 Year/Week。
输出 2:在交付缺口之前找到 Year/Week。
下面是 Excel 工作表 1 上的原始数据布局和工作表 2 上的分析的示例图像。
Image of Excel issue:
这段代码应该可以满足您的要求,但请检查它是否没有出错。 我没有检查太多,所以它可能会产生错误。 运行 它在工作簿的副本中。
你应该将它放入 class 模块并命名为 'CItem':
Public pItemDescription As String
Public pSupplier As String
Public pDateDelivery As Collection
https://excelmacromastery.com/vba-class-modules/
'Analysis' 中的 table 应该是空的。
然后进入常规模块:
Option Explicit
Sub SortCheck()
Dim aSht As Worksheet
Dim bSht As Worksheet
Dim tempItemDescription As String
Dim tempSupplier As String
Dim tempDateDelivery As String
Dim xItemsAll As Collection
Dim xItem As CItem
Dim xI As Variant
Dim flag As Boolean
Dim xTemp As Variant
Dim i As Long
Dim j As Long
Dim k As Long
Dim Row As Long
Set xItemsAll = New Collection
Set xItem = New CItem
Set aSht = Worksheets("Raw Data")
Set bSht = Worksheets("Analysis")
Row = 2
flag = True
Do
' If the cell is empty, stop populating the collection
If aSht.Cells(Row, 2).Value = "" Then Exit Do
' ---
tempDateDelivery = aSht.Cells(Row, 1).Value
tempItemDescription = aSht.Cells(Row, 2).Value
tempSupplier = aSht.Cells(Row, 3).Value
'If xItemsAll contains some records, check wheter similar records exist
If xItemsAll.Count > 0 Then
For Each xI In xItemsAll
If tempItemDescription = xI.pItemDescription And tempSupplier = xI.pSupplier Then
Set xItem = New CItem
Set xItem = xI
xItem.pDateDelivery.Add tempDateDelivery
Set xItem = Nothing
flag = False
Exit For
Else
flag = True
End If
Next xI
End If
' If the first pass or no element in collection yet, create new record
If flag = True Then
Set xItem = New CItem
With xItem
.pItemDescription = tempItemDescription
.pSupplier = tempSupplier
Set .pDateDelivery = New Collection
.pDateDelivery.Add tempDateDelivery
End With
xItemsAll.Add xItem
Set xItem = Nothing
flag = False
End If
Row = Row + 1
Loop
'Sort the collection - Item Description in order
For i = 1 To xItemsAll.Count - 1
For j = i + 1 To xItemsAll.Count
If xItemsAll(i).pItemDescription > xItemsAll(j).pItemDescription Then
Set xItem = New CItem
Set xItem = xItemsAll(j)
xItemsAll.Remove j
If j <> xItemsAll.Count + 1 Then
xItemsAll.Add xItemsAll(i), , j
Else
xItemsAll.Add xItemsAll(i), , , j - 1
End If
xItemsAll.Remove i
If i <> xItemsAll.Count + 1 Then
xItemsAll.Add xItem, , i
Else
xItemsAll.Add xItem, , , i - 1
End If
Set xItem = Nothing
End If
Next j
Next i
'Sort the collection - Suplier in order
For i = 1 To xItemsAll.Count - 1
For j = i + 1 To xItemsAll.Count
If xItemsAll(i).pItemDescription = xItemsAll(j).pItemDescription Then
If xItemsAll(i).pSupplier > xItemsAll(j).pSupplier Then
Set xItem = New CItem
Set xItem = xItemsAll(j)
xItemsAll.Remove j
If j <> xItemsAll.Count + 1 Then
xItemsAll.Add xItemsAll(i), , j
Else
xItemsAll.Add xItemsAll(i), , , j - 1
End If
xItemsAll.Remove i
If i <> xItemsAll.Count + 1 Then
xItemsAll.Add xItem, , i
Else
xItemsAll.Add xItem, , , i - 1
End If
Set xItem = Nothing
End If
End If
Next j
Next i
'Sort the collection - Dates in order
For k = 1 To xItemsAll.Count
For i = 1 To xItemsAll(k).pDateDelivery.Count - 1
For j = i + 1 To xItemsAll(k).pDateDelivery.Count
If xItemsAll(k).pItemDescription = xItemsAll(k).pItemDescription Then
If xItemsAll(k).pSupplier = xItemsAll(k).pSupplier Then
If xItemsAll(k).pDateDelivery(i) > xItemsAll(k).pDateDelivery(j) Then
xTemp = xItemsAll(k).pDateDelivery(j)
xItemsAll(k).pDateDelivery.Remove j
If j <> xItemsAll(k).pDateDelivery.Count + 1 Then
xItemsAll(k).pDateDelivery.Add xItemsAll(k).pDateDelivery(i), , j
Else
xItemsAll(k).pDateDelivery.Add xItemsAll(k).pDateDelivery(i), , , j - 1
End If
xItemsAll(k).pDateDelivery.Remove i
If i <> xItemsAll(k).pDateDelivery.Count + 1 Then
xItemsAll(k).pDateDelivery.Add xTemp, , i
Else
xItemsAll(k).pDateDelivery.Add xTemp, , , i - 1
End If
End If
End If
End If
Next j
Next i
Next k
Row = 2
For i = 1 To xItemsAll.Count
For j = 1 To xItemsAll(i).pDateDelivery.Count - 1
If CLng(Mid(xItemsAll(i).pDateDelivery(j + 1), 5)) <> (CLng(Mid(xItemsAll(i).pDateDelivery(j), 5)) + 1) Then
bSht.Cells(Row, 1).Value = xItemsAll(i).pDateDelivery(j + 1)
bSht.Cells(Row, 2).Value = xItemsAll(i).pDateDelivery(j)
bSht.Cells(Row, 3).Value = xItemsAll(i).pItemDescription
bSht.Cells(Row, 4).Value = xItemsAll(i).pSupplier
Row = Row + 1
End If
Next j
Next i
End Sub
要使代码正常工作,它必须是 201801、201805 等,而不是 20181、20185 等。因此,如果您有不同的代码,则必须使用函数或 vba 修改它。