【问题标题】:VBA loop isn't functioning properlyVBA 循环无法正常运行
【发布时间】:2017-02-01 18:39:53
【问题描述】:
Sub Button2_Click()
Dim i As Integer, q As Integer
i = 2
q = 2
Do While i < 468 And q < 3450
If Worksheets("Sheet1").Range("A" & i).Value = Worksheets("Sheet2").Range("A" & q).Value Then
    If Len(Worksheets("Sheet1").Cells(i, 4)) < 12 Then
        Dim edate As String, adate As String, ed As String, ad As String, n As Integer, x As Integer, y As Integer
        edate = Sheets("sheet1").Cells(i, 4).Value
        adate = Sheets("sheet2").Cells(q, 2).Value
        ed = Right(Sheets("sheet1").Cells(i, 4), 4)
        ad = Right(Sheets("sheet2").Cells(q, 2), 4)
        n = CInt(ad) - CInt(ed)
        If InStr(edate, "Fall") And InStr(adate, "Fall") Then x = 7 + (5 * n)
        If InStr(edate, "Fall") And InStr(adate, "Spring") Then x = 9 + (5 * (n - 1))
        If InStr(edate, "Spring") And InStr(adate, "Spring") Then x = 9 + (5 * n)
        If InStr(edate, "Spring") And InStr(adate, "Fall") Then x = 12 + (5 * n)
        y = x - 1
        Worksheets("Sheet1").Cells(i, x).Value = Worksheets("Sheet2").Cells(q, 5).Value
        Worksheets("Sheet1").Cells(i, y).Value = Worksheets("Sheet2").Cells(q, 3).Value
        i= i +1
        q=2
    Else
        i = i + 1
        q = 2
    End If
Else
    If q < 3423 Then
        q = q + 1
    else
        i = 1 + 1
        q=2
    End If
    Else
        i = i + 1
        q = 2
    End If
End If
Loop
End Sub

大家好,上面的代码是我一直在处理的一些重要数据,从 sheet2 到 sheet1。表 2 第 1 列有项目 ID 编号,第 2 列有期限(授予日期),第 3 列有奖励类型,第 5 列有金额。第 1 列第 1 列有项目 ID,第 4 列有期限(入职日期)。表 2 具有按学期授予的奖项并按项目 ID 进行索引,我想重视数据并将它们放入由 if instr 语句给出的列中,并位于文本中间。

此代码的目标是遍历表 1 A 列中的项目 ID 号并检查它们是否存在于表 2 A 列中,然后导入按年份差异排序的奖励类型和金额在表 1 上的输入日期和表 2 上的授予日期之间。日期有春季/秋季和一年,所以我尝试了 left(string, #) 命令只减去年份,然后是上述 if 的块instr 代码应该可以平衡学期之间的差异。

工作表 2 中有多个相同的项目 ID,因此我需要代码在工作表 2 的上一行之后恢复循环,直到工作表 1 上的每个项目 ID 都被交叉引用。

有人能指出我的代码中的错误吗?单击命令按钮时没有任何反应。

问题出在第一个 if 语句中,当我知道至少有 450 个数据匹配时,它会跳过所有需要满足条件的操作。

刚刚编辑了我的代码,它现在还在运行。

由于 cmets 的编辑列表:修复了逻辑语句问题、修复了范围/单元格/单元格问题、修复了循环问题、修复了右/左字符串问题

【问题讨论】:

  • i = i + 1 And q = 2 真的是一个逻辑表达式,还是两个语句,即i = i + 1: q = 2
  • 当我单击命令按钮时没有任何反应 - 是否尝试通过 debugging 指出代码中的错误(运行逐行代码并通过检查变量值等查看结果。
  • 在应该使用语句分隔符时不要使用逻辑运算符。
  • Sub Button2_Click() 之后创建一个MessageBox 以确保脚本正在运行。
  • 你确定它们是数字吗?将格式切换为一般格式并确保前导零消失,或使用"#,##0" 格式并确保出现逗号。 (附言一旦你越过了那条线,你的 .cell 方法将失败。它们应该是 .Cells 属性。)如果它们是 9 位数字,你为什么还要使用 Like,你不想检查一下吗?平等?

标签: database excel vba loops


【解决方案1】:

我可以建议你重构你的代码如下:

Sub Button2_Click()
    Dim i As Integer, q As Integer
    'Storing the ids in an array will make it much faster to access instead
    'of interfacing with Excel's object model a couple of million times
    Dim ids1, ids2
    Dim origCalcMode As XlCalculation

    'Switch off ScreenUpdating to improve speed
    Application.ScreenUpdating = False
    'Switch off auto calculation to improve speed
    origCalcMode = Application.Calculation
    Application.Calculation = xlCalculationManual

    ids1 = Application.Transpose(Worksheets("Sheet1").Range("A2:A467").Value)
    ids2 = Application.Transpose(Worksheets("Sheet2").Range("A2:A3422").Value)
    'Using For loops rather than manually keeping track of row counters
    'makes the code MUCH cleaner and less prone to errors
    For i = 2 To 467
        'Moving this test to earlier in the code avoids having to iterate
        'through all the rows on Sheet2 when there is nothing that can be
        'done with the matching data anyway
        If Len(Worksheets("Sheet1").Cells(i, 4)) < 12 Then
            For q = 2 To 3422
                If ids1(i - 1) = ids2(q - 1) Then
                    Dim edate As String, adate As String, ed As String, ad As String, n As Integer, x As Integer, y As Integer
                    edate = Sheets("sheet1").Cells(i, 4).Value
                    adate = Sheets("sheet2").Cells(q, 2).Value
                    ed = Right(Sheets("sheet1").Cells(i, 4), 4)
                    ad = Right(Sheets("sheet2").Cells(q, 2), 4)
                    n = CInt(ad) - CInt(ed)
                    If InStr(edate, "Fall") And InStr(adate, "Fall") Then x = 7 + (5 * n)
                    If InStr(edate, "Fall") And InStr(adate, "Spring") Then x = 9 + (5 * (n - 1))
                    If InStr(edate, "Spring") And InStr(adate, "Spring") Then x = 9 + (5 * n)
                    If InStr(edate, "Spring") And InStr(adate, "Fall") Then x = 12 + (5 * n)
                    y = x - 1
                    Worksheets("Sheet1").Cells(i, x).Value = Worksheets("Sheet2").Cells(q, 5).Value
                    Worksheets("Sheet1").Cells(i, y).Value = Worksheets("Sheet2").Cells(q, 3).Value
                    Exit For
                End If
            Next
        End If
    Next

    'Restore application settings
    Application.ScreenUpdating = True
    Application.Calculation = origCalcMode
End Sub

我不确定Exit For 行。您的问题意味着您需要处理 Sheet2 中的多个条目(如果存在)。如果是这样,请删除 Exit For 行,但这会增加运行时间,因为它需要为 Sheet1 中的每一行遍历 Sheet2 中的所有 3421 行。

编辑:根据 BruceWayne 的建议,包括对 ScreenUpdating 和 Calculation 的更改。

【讨论】:

  • @xpes100 - 什么都没有发生?如果您使用F8 单步执行代码,您可以将鼠标悬停在变量上,看看它是否按照您的预期更新它们,或者您可以“跟踪”宏出错的地方。
  • @BruceWayne - 上面的 OP 评论是我第一次尝试回答问题时留下的(即当代码包含 i = i + 1 And q = 2 时)。显然 OP 的代码现在正在运行(或者,至少,正在做某事),但只是需要很长时间才能运行。
  • 你认为关闭自动计算和屏幕更新对速度有帮助吗?
  • @BruceWayne - 可能有点帮助,但最多有 932 个单元格写入,所以我看不到屏幕更新是导致缓慢的主要原因,我猜测不会有很多计算依赖于更新的单元格(它似乎不是计算密集型的应用程序)。无论如何我都会编辑代码。
  • 一开始不喜欢使用With Worksheets("Sheet1") 吗?会使代码更简洁更短。
【解决方案2】:

感谢您的所有帮助,这里的代码可以在任何人偶然发现类似问题的情况下使用。

此代码循环遍历带有整数 i 的 sheet1 和带有整数 q 的 sheet2 以在两张表的第一/A 列中查找匹配项。由于我在 A 列的 sheet2 上有多个项目想法(表 1 列 A),因此在 sheet2 上的行 (q) 找到匹配项后,它会继续。然后继续遍历指定数量的行 (i),然后遍历每个 i 的所有行 (q)。

Public CalcState As Long
Public EventState As Boolean
Public PageBreakState As Boolean

Sub OptimizeCode_Begin()

Application.ScreenUpdating = False

EventState = Application.EnableEvents
Application.EnableEvents = False

CalcState = Application.Calculation
Application.Calculation = xlCalculationManual

PageBreakState = ActiveSheet.DisplayPageBreaks
ActiveSheet.DisplayPageBreaks = False

End Sub

Sub OptimizeCode_End()

ActiveSheet.DisplayPageBreaks = PageBreakState
Application.Calculation = CalcState
Application.EnableEvents = EventState
Application.ScreenUpdating = True

End Sub


Sub Button2_Click()
Dim i As Integer, q As Integer, origCalcMode As XlCalculation
i = 3
q = 2
Call OptimizeCode_Begin
Do While i < 467
If Len(Worksheets("Sheet1").Cells(i, 4)) < 12 Then
    If Worksheets("Sheet1").Cells(i, 1).Value = Worksheets("Sheet2").Cells(q, 1).Value Then
        Dim edate As String, adate As String, ed As String, ad As String, n As Integer, x As Integer, y As Integer
        edate = Sheets("sheet1").Cells(i, 4).Value
        adate = Sheets("sheet2").Cells(q, 2).Value
        ed = Right(Sheets("sheet1").Cells(i, 4), 4)
        ad = Right(Sheets("sheet2").Cells(q, 2), 4)
        n = CInt(ad) - CInt(ed)
        If InStr(edate, "Fall") And InStr(adate, "Fall") Then x = 7 + (5 * n)
        If InStr(edate, "Fall") And InStr(adate, "Spring") Then x = 9 + (5 * (n - 1))
        If InStr(edate, "Spring") And InStr(adate, "Spring") Then x = 9 + (5 * n)
        If InStr(edate, "Spring") And InStr(adate, "Fall") Then x = 12 + (5 * n)
        y = x - 1
        Worksheets("Sheet1").Cells(i, x).Value = Worksheets("Sheet2").Cells(q, 5).Value
        Worksheets("Sheet1").Cells(i, y).Value = Worksheets("Sheet2").Cells(q, 3).Value
        q = q + 1
    Else
        If q < 1236 Then
            q = q + 1
        Else
            i = i + 1
            q = 2
        End If
    End If
Else
   i = i + 1
   q = 2
End If
Loop
Call OptimizeCode_End
End Sub

【讨论】:

    猜你喜欢
    • 2013-08-09
    • 2015-05-16
    • 1970-01-01
    • 2023-03-28
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 2020-12-18
    • 2020-01-31
    相关资源
    最近更新 更多