【问题标题】:Merging over 2000 Cells using VBA?使用 VBA 合并 2000 多个单元格?
【发布时间】:2015-07-09 01:23:15
【问题描述】:

我写了以下代码来合并excel中的单元格,数据大约26000行,代码运行在8 GB RAM的核心I7 CPU上,问题是它仍然工作4天,平均每天的行数是3000行!,任何人都知道如何得到结果,因为它的报告应该从三天内交付!

Sub MergeCellss()
lastRow = Worksheets("A").Range("A65536").End(xlUp).Row

Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DisplayAlerts = False

For i = 2 To lastRow
If Cells(i, 2).Value <> Cells(i - 1, 2).Value And Cells(i, 2).Value <> Cells(i + 1, 2).Value Then
     intUpper = i
     Debug.Print ("<> -1 and <> +1 " & intUpper)
End If

If Cells(i, 2).Value <> Cells(i - 1, 2).Value And Cells(i, 2).Value = Cells(i + 1, 2).Value Then
     intUpper = i
     Debug.Print ("<> -1 and = +1 " & intUpper & " UPPPER LIMIT")
End If


If Cells(i, 2).Value <> Cells(i + 1, 2).Value And Cells(i, 2).Value = Cells(i - 1, 2).Value Then
    Application.DisplayAlerts = False
      Debug.Print ("<> +1 and = -1:" & i & "LOWER LIMIT")
        DoEvents
         For x = 1 To 8
             Range(Cells(intUpper, x), Cells(i, x)).Merge
        Next x

        For j = 18 To 26
             Range(Cells(intUpper, j), Cells(i, j)).Merge
        Next j
        Cells(intUpper, 14).Value = "=sumif(M" & CStr(intUpper) & ":M" & CStr(i) & ","">0"")"
        Range(Cells(intUpper, 14), Cells(i, 14)).Merge
        Range(Cells(i, 1), Cells(i, 26)).Borders(xlEdgeBottom).LineStyle = xlDouble
End If

If Cells(i, 2).Value <> Cells(i + 1, 2).Value And Cells(i, 2).Value <> Cells(i - 1, 2).Value Then
     Debug.Print ("One Cells: " & i)
    Range(Cells(i, 1), Cells(i, 26)).Borders(xlEdgeBottom).LineStyle = xlDouble
      Cells(intUpper, 14).Value = Cells(intUpper, 13).Value
      DoEvents
End If

Next i
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.DisplayAlerts = True
End Sub

上面的代码会将包含重复数据(如用户名、出生日期……)的所有单元格合并到一个单元格中,并保持培训课程和经验不变。

我想知道如何在不到 1 小时的时间内运行此代码。

【问题讨论】:

  • 您可以先发布一些示例数据和预期结果。
  • 您执行的If 检查至少是您需要的两倍。前两个If ... End If : If ... End If 应该是一个If ... ElseIf ...End If。最常为 True 的条件应该是第一个检查的条件。如果第一个为真,则第二个不能为真,因此使用ElseIf 会跳过该计算。第二对也是如此。不幸的是,您不能ElseIf它们全部,因为被检查的单元格从前两个变为后两个,但即使将它们配对也应该大大减少计算。大型变体数组会将 calc 减少到现在的
  • 我很抱歉 - 看起来后两个 If 语句可以使用 ElseIf 嵌套到前两个语句中。我没有意识到你翻转了单元格引用并认为它们是不同的单元格,但事实并非如此。如果这四个条件中的任何一个为真,则其他三个都不为真,因此无需检查它们。
  • 您是否打算在某个时候发布指向已编辑数据的公共链接?在不了解数据性质的情况下继续下去是没有意义的。我能推测的最好的是 B 列包含日期,并且三行之间关系的切换会触发不同的事件。
  • @JohnColeman - 我同意。一台较旧的 i5/8Gb 笔记本电脑在 57 秒内运行了 24K 行数据,但我无法知道实际数据会产生多少每次操作。我担心后台进程正在征用DoEvents。我会发布一些修改过的代码,以防 OP 想尝试一下。

标签: vba excel merge


【解决方案1】:

这是对您的代码的一些重写。两个主要区别是If ... ElseIf ... End If 的使用以及第一个和第四个条件操作的分组(条件相同)。

Sub Merge_Cells()
    Dim lastRow As Long, rw As Long
    Dim intUpper As Long, x As Long
    Dim vVALs As Variant

    appTGGL bTGGL:=False
    Debug.Print Timer

    With Worksheets("A")
        .Cells(1, 1) = Timer
        lastRow = .Cells(Rows.Count, 1).End(xlUp).Row

        For rw = 2 To lastRow
            vVALs = Array(.Cells(rw - 1, 2).Value, .Cells(rw, 2).Value, .Cells(rw + 1, 2).Value)

            If vVALs(1) <> vVALs(0) And vVALs(1) <> vVALs(2) Then
                'the first and fourth conditions were the same so they are both here
                'original first If condition
                intUpper = rw
                'Debug.Print ("<> -1 and <> +1 " & intUpper)
                'original fourth If condition
                'Debug.Print ("One Cells: " & rw)
                .Range(.Cells(rw, 1), .Cells(rw, 26)).Borders(xlEdgeBottom).LineStyle = xlDouble
                .Cells(intUpper, 14).Value = .Cells(intUpper, 13).Value
            ElseIf vVALs(1) <> vVALs(0) And vVALs(1) = vVALs(2) Then
                 intUpper = rw
                 'Debug.Print ("<> -1 and = +1 " & intUpper & " UPPPER LIMIT")
            ElseIf vVALs(1) = vVALs(0) And vVALs(1) <> vVALs(2) Then
                'Debug.Print ("<> +1 and = -1:" & rw & "LOWER LIMIT")

                For x = 1 To 26
                    If x < 9 Or x > 17 Then _
                        .Range(.Cells(intUpper, x), .Cells(rw, x)).Merge
                Next x

                .Cells(intUpper, 14).Value = "=sumif(M" & CStr(intUpper) & ":M" & CStr(rw) & ","">0"")"
                .Range(.Cells(intUpper, 14), .Cells(rw, 14)).Merge
                .Cells(rw, 1).Resize(1, 26).Borders(xlEdgeBottom).LineStyle = xlDouble
            End If

        Next rw
        .Cells(1, 2) = Timer
    End With

    Debug.Print Timer
    appTGGL
End Sub

Sub appTGGL(Optional bTGGL As Boolean = True)
    Application.Calculation = IIf(bTGGL, xlCalculationAutomatic, xlCalculationManual)
    Application.ScreenUpdating = bTGGL
    Application.EnableEvents = bTGGL
    Application.DisplayAlerts = bTGGL
End Sub

我还将三个主要条件值读入一个变量数组,以减少重复读取工作表值。

【讨论】:

  • 感谢代码,我在 20 分钟前运行了它,还在等待它完成第一个计时器显示 (debug.print Timer) 是 25895.95,这是数据的快照 tinypic.com?ref=2vkn886" target="_blank">