excel - 如何有效控制多个嵌套循环而不会出现 RT 错误?
问题描述
我一直在玩这个代码一段时间了。我希望它写得足够好,可以被理解。我正在尝试做一个查询,首先尝试匹配两个值,项目描述。如果成功,如果材料代码匹配,我还想从同一行中进行下一步。如果它们都匹配,那么在价格匹配的同一行上,我想从 SF 获取结果并将其带入 SAP。
收到的错误是“用于控制已在使用中”,我有点收集。请问这将如何适当地完成?
见下文
Private Sub CommandButton1_Click()
Dim SAP As Range
Set SAP = ThisWorkbook.Worksheets("SAP").UsedRange
Dim SF As Range
Set SF = ThisWorkbook.Worksheets("SF").UsedRange
Dim SAPProjectDesc As Range
Set SAPProjectDesc = SAP.Columns(5)
Dim SFProjectDesc As Range
Set SFProjectDesc = SF.Columns(4)
Dim SAPSFBuyPrice As Range
Set SAPSFBuyPrice = SAP.Columns(16)
Dim SAPSFSellPrice As Range
Set SAPSFSellPrice = SAP.Columns(17)
Dim SFBuyPrice As Range
Set SFBuyPrice = SF.Columns(27)
Dim SFSellPrice As Range
Set SFSellPrice = SF.Columns(25)
Dim SFMaterialCode As Range
Set SFMaterialCode = SF.Columns(23)
Dim SAPMaterialCode As Range
Set SAPMaterialCode = SAP.Columns(14)
Dim i As Long
Dim c As Range
For i = 2 To SAPProjectDesc.Rows.Count
For Each c In SFProjectDesc.Cells
If c.Value2 = SAPProjectDesc.Rows(i).Value2 Then
For Each c In SFMaterialCode.Cells
If c.Value2 = SAPMaterialCode.Rows(i).Value2 Then
''MATCH CODE GOES HERE
J = c.Row
SAP.Activate
SAPSFSellPrice.Rows(i).Activate
SAPSFSellPrice.Rows(i).Value2 = SFSellPrice.Rows(J).Value2
SAPSFBuyPrice.Rows(i).Value2 = SFBuyPrice.Rows(J).Value2
Else
''Found a Project but not a material code
MsgBox "Found a Project Name Match but not a material Code match"
End If
Next
Else
''Didnt find a project match
MsgBox "Didnt Find a Project Match"
End If
Next
Next
End Sub
解决方案
更新工作表
- 第一个代码
updatePricesQF
是中间慢速快速修复(独立)。我相信你能弄清楚。 - 第二,主要代码
updatePrices
,是一个先进的快速解决方案。它正在使用剩下的两个程序。它可能仍然可以优化以运行得更快,但我已经拥有它。 - 通常将代码复制到标准模块(例如
Module1
)中,然后使用Call updatePrices
或仅updatePrices
在命令按钮单击事件代码中使用,这也使得它更容易应用于许多按钮。
编码
Option Explicit
Sub updatePricesQF() ' Slow: it took 45 sec for 10000 rows of values only.
' SF (Source)
Dim SF As Range: Set SF = ThisWorkbook.Worksheets("SF").UsedRange
Dim SFProjectDesc As Range: Set SFProjectDesc = SF.Columns(4)
Dim SFMaterialCode As Range: Set SFMaterialCode = SF.Columns(23)
Dim SFBuyPrice As Range: Set SFBuyPrice = SF.Columns(27)
Dim SFSellPrice As Range: Set SFSellPrice = SF.Columns(25)
' SAP (Target)
Dim SAP As Range: Set SAP = ThisWorkbook.Worksheets("SAP").UsedRange
Dim SAPProjectDesc As Range: Set SAPProjectDesc = SAP.Columns(5)
Dim SAPMaterialCode As Range: Set SAPMaterialCode = SAP.Columns(14)
Dim SAPBuyPrice As Range: Set SAPBuyPrice = SAP.Columns(16)
Dim SAPSellPrice As Range: Set SAPSellPrice = SAP.Columns(17)
' Program
Application.ScreenUpdating = False
Dim Pro As Variant, Mat As Variant, i As Long, k As Long
For i = 2 To SAPProjectDesc.Rows.Count
Pro = SAPProjectDesc.Rows(i).Value
Mat = SAPMaterialCode.Rows(i).Value
For k = 2 To SFProjectDesc.Rows.Count
If SFProjectDesc.Rows(k) = Pro Then
If SFMaterialCode.Rows(k).Value = Mat Then
SAPSellPrice.Rows(i).Value = SFSellPrice.Rows(k).Value
SAPBuyPrice.Rows(i).Value = SFBuyPrice.Rows(k).Value
Exit For ' Only one combination of "ProjectDesc" and
' "MaterialCode" in "SF" is expected.
End If
End If
Next
Next
Application.ScreenUpdating = True
MsgBox "Prices updated.", vbInformation, "Success"
End Sub
Sub updatePrices() ' Fast: it took 3 sec for 10000 rows of values only.
' SF
Const srcName As String = "SF"
Const srcFirstRow As Long = 2
Const srcLastRowCol As Variant = 4
Dim srcCols As Variant: srcCols = Array(4, 23, 27, 25)
' SAP
Const tgtName As String = "SAP"
Const tgtFirstRow As Long = 2
Const tgtLastRowCol As Variant = 5
Dim tgtCols As Variant: tgtCols = Array(5, 14, 16, 17)
' Other
Dim wb As Workbook: Set wb = ThisWorkbook
' Write columns to arrays.
Dim rng As Range, j As Long
Dim ubc As Long: ubc = UBound(srcCols)
' Write values of Source Columns to jagged Source Array.
Dim src As Worksheet: Set src = wb.Worksheets(srcName)
getColumnRangeUsingColumnID rng, src, srcLastRowCol, srcFirstRow
If rng Is Nothing Then Exit Sub
Dim Source As Variant: ReDim Source(ubc)
For j = 0 To ubc
getRange Source(j), rng.Offset(, srcCols(j) - srcLastRowCol)
Next j
' Write values of Target Columns to jagged Target Array.
Dim tgt As Worksheet: Set tgt = wb.Worksheets(tgtName)
getColumnRangeUsingColumnID rng, tgt, tgtLastRowCol, tgtFirstRow
If rng Is Nothing Then Exit Sub
Dim Target As Variant: ReDim Target(ubc)
For j = 0 To ubc
getRange Target(j), rng.Offset(, tgtCols(j) - tgtLastRowCol)
Next j
' Modify values in jagged Target Array.
Dim ubt As Variant: ubt = UBound(Target(0))
Dim ubs As Variant: ubs = UBound(Source(0))
Dim Pro As Variant, Mat As Variant, i As Long, k As Long
For i = 1 To ubt
Pro = Target(0)(i, 1)
Mat = Target(1)(i, 1)
For k = 1 To ubs
If Source(0)(k, 1) = Pro Then
If Source(1)(k, 1) = Mat Then
For j = 2 To 3
Target(j)(i, 1) = Source(j)(k, 1)
Next j
Exit For
End If
End If
Next k
Next i
' Copy values from jagged Target Array to Target Column Ranges.
For j = 2 To 3
rng.Offset(, tgtCols(j) - tgtLastRowCol).Value = Target(j)
Next j
' Inform user.
MsgBox "Prices updated.", vbInformation, "Success"
End Sub
' Writes the values of a range to a 2D one-based array.
Sub getRange(ByRef Data As Variant, SourceRange As Range)
Data = Empty
If SourceRange Is Nothing Then Exit Sub
If SourceRange.Rows.Count > 1 Or SourceRange.Columns.Count > 1 Then
Data = SourceRange.Value
Else
ReDim Data(1 To 1, 1 To 1): Data(1, 1) = SourceRange.Value
End If
End Sub
' Defines the column range of a given column starting from a given
' first row and ending with the last non-blank cell.
' If NoEmpties is set to True, it will not consider the bottom cells possibly
' containing a formula evaluating to "".
Sub getColumnRangeUsingColumnID(ByRef ColumnRange As Range, _
Optional Sheet As Worksheet = Nothing, _
Optional ByVal ColumnID As Variant = 1, _
Optional ByVal FirstRow As Long = 1, _
Optional ByVal NoEmpties As Boolean = False)
Set ColumnRange = Nothing
If Sheet Is Nothing Then Set Sheet = ActiveSheet
Dim FormVal As XlFindLookIn
If NoEmpties Then FormVal = xlValues Else FormVal = xlFormulas
Dim rng As Range
Set rng = Sheet.Columns(ColumnID).Find("*", , FormVal, , , xlPrevious)
If rng Is Nothing Then Exit Sub ' Empty Column.
If rng.Row < FirstRow Then Exit Sub ' Last Row is below First Row.
Set ColumnRange = Sheet.Range(Sheet.Cells(FirstRow, ColumnID), rng)
End Sub
推荐阅读
- php - 在 PHP 中使用不同的访问令牌进行 API 调用
- json - 获取多个复选框值作为角度数组
- .net-core - 将 ServiceStack Redis 使用推送到 Application Insights 依赖项遥测
- mysql - 带有 sql 的 Nodejs
- python - 如何通过 django 视图调度 celery 任务
- json - (Django) 安装夹具“rules.json”时出现问题:“NoneType”对象没有属性“id”
- c# - 如何在c#后面的代码中动态地向html添加新元素
- c# - Hololens2 和 Unity:使用 QR 码放置与其相关的对象/标记
- android - 如何创建切换按钮效果?
- selenium - 获取异常:org.openqa.selenium.WebDriverException:未知错误:net::ERR_NAME_NOT_RESOLVED