【问题标题】:Loop to change range based on sum of cell循环以根据单元格的总和更改范围
【发布时间】:2022-09-27 12:03:01
【问题描述】:

我正在尝试将范围调整为连续大于 0 值的单元格。

我有 12 列,每个月一个。我想从包含数据的单元格中创建一个范围。

我的代码循环一次并在第 11 个月停止。

Sub Charts_Update()

Dim TotFTE As Range, CellIndex As Range
Dim ColIndex As Long, i As Long

Set TotFTE = Sheets(\"FTE Detail\").Range(\"E19:P19\")

i = 12
    
With TotFTE
    For ColIndex = .Cells(0, 16).End(xlToLeft).Column To 5 Step -1
        With Columns(ColIndex)
            If Application.Sum(.Cells) = 0 Then
                i = i - 1
                Set TotFTE = TotFTE.Offset(0, 0).Resize(1, i)
            End If
        End With
    Next ColIndex
End With

End Sub
  • 为什么.Cells(0, 16) 处的索引为 0?不应该是1吗?
  • 可能从第一个 0 值 application.match(0,\"range\",false) 开始,到 .end(xltoright).column1
  • 您正在对整列的单元格求和。不仅如此,即使您的宏找到非零结果,它也不会停止检查零。如果只能有没有间隙的连续数据,则代码将毫无意义地运行。如果您可以有日期与间隙,则代码将丢失第一个数据间隙右侧的所有数据。为什么要使用如此复杂的方式而不是 Range.End(嵌入在 If 语句中以覆盖单列数据)?你有实际的 0 作为数据吗?

标签: excel vba


【解决方案1】:

根据您想要实现的目标,我有多个可能的代码。在任何情况下,如果没有找到具有数值的单元格(我保持了您通过Application.Sum 制定条件的方式)或无法以任何其他方式确定适当的范围,则不会返回任何内容。

第一个是您自己的代码的修改版本:

Sub Charts_Update1()
    
    'Declarations.
    Dim TotFTE As Range, CellIndex As Range
    Dim ColIndex As Long, i As Long
    
    'Settings
    Set TotFTE = Sheets("FTE Detail").Range("E19:P19")
    i = TotFTE.Columns.Count
    
    'Focusing TotFTE.
    With TotFTE
        
        'Covering the cells from the most right cell with data to the left of cell(0, 16) to the firt column of TotFTE.
        For ColIndex = .Cells(0, 16).End(xlToLeft).Column To TotFTE.Column Step -1
            
            'Focusing the entire column with ColIndex index.
            With Columns(ColIndex)
                
                'Checking if the sum of the cell of TotFTE within the column with ColIndex index is 0.
                If Application.Sum(Intersect(.Cells, TotFTE)) = 0 Then
                    
                    'Setting i for the previous column.
                    i = i - 1
                    
                    'If i is equal to 0, no result with a sum different from 0 has been found.
                    If i = 0 Then
                        
                        'Setting TotFTE to nothing and terminating the macro.
                        Set TotFTE = Nothing
                        Exit Sub
                        
                    End If
                    
                    'Resizing TotFte.
                    Set TotFTE = TotFTE.Resize(1, i)
                Else
                    
                    'The first cell with a sum different than 0 most to the right in TotFTE has been found. The macro is terminated.
                    Exit Sub
                    
                End If
                
            End With
            
        Next ColIndex
        
    End With

End Sub

它将返回范围:

  • 来自原始 TotFTE 左边缘的单元格(即使为空或带有文本)
  • 到原始 TotFTE 右边缘左侧的第一个最右边的非空非文本值

我希望至少有一个代码是您自己的修改版本。因此,我将保持一些关键性(例如使用标头来确定ColIndex)。


第二个是全新的代码:

Sub Charts_Update2()
    
    'Declarations.
    Dim TotFTE As Range
    Dim RngTarget As Range
    
    'Settings.
    Set TotFTE = Sheets("FTE Detail").Range("E19:P19")
    Set RngTarget = TotFTE.Cells(1, 1)
    
    'If the sum of RngTarget is zero, TotFTE is set to nothing and the macro is terminated.
    If Application.Sum(RngTarget) = 0 Then
        Set TotFTE = Nothing
        Exit Sub
    End If
    
    'RngTarget is resized until its sum doesn't change anymore or it reaches the TotFTE range limit.
    Do Until Application.Sum(RngTarget) = Application.Sum(RngTarget.Resize(, RngTarget.Columns.Count + 1)) Or _
             RngTarget.Columns.Count + 1 > TotFTE.Columns.Count
        Set RngTarget = RngTarget.Resize(, RngTarget.Columns.Count + 1)
    Loop
    
    'Setting TotFTE.
    Set TotFTE = RngTarget
    
End Sub

它将返回范围:

  • 仅当非空且非文本值时才从原始 TotFTE 的左边缘开始
  • 到原始 TotFTE 内第一个连续令人满意(非空,非文本值)数据块右边缘的单元格。

第三个也是全新的代码:

Sub Charts_Update3()
    
    'Declarations.
    Dim TotFTE As Range
    Dim RngLeft As Range
    Dim RngRight As Range
    
    'Settings.
    Set TotFTE = Sheets("FTE Detail").Range("E19:P19")
    Set RngLeft = TotFTE.Cells(1, 1)
    Set RngRight = TotFTE.Cells(1, TotFTE.Columns.Count)
    
    'Checking if RngLeft sum is zero.
    If Application.Sum(RngLeft.Value) = 0 Then
        
        'Setting RngLeft as the firt cell with value to the right of RngLeft.
        Set RngLeft = RngLeft.End(xlToRight)
        
        'Checking if RngLeft has reached beyond the TotFTE limits or has a sum total of 0.
        If RngLeft.Column > TotFTE.Column + TotFTE.Columns.Count - 1 Or Application.Sum(RngLeft.Value) = 0 Then
            
            'Setting TotFTE to nothing end terminating the sub.
            Set TotFTE = Nothing
            Exit Sub
        End If
    End If
    
    'Checking if RngLeft sum is zero.
    If Application.Sum(RngRight.Value) = 0 Then
        'Setting RngRight as the firt cell with value to the left of Rngright.
        Set RngRight = RngRight.End(xlToLeft)
    End If
    
    'Setting TotFTE.
    Set TotFTE = Range(RngRight, RngLeft)
    
End Sub

它将返回范围:

  • 从原始 TotFTE 最左边的单元格开始,非空且非文本值
  • 到原始 TotFTE 的最右侧单元格,该单元格非空且非文本值。

它将包括这两个单元格之间的任何空值和/或文本值。

【讨论】:

  • 哇!完全没想到会有这么深入的回答!第二个代码正是我想要做的——我没有意识到我正在检查整个列而不是范围内的单元格,这导致它停止,因为我在上面几行有一个数字日期。此外,就像@user1236777 提到的那样,它正在删除包含数据的列(包含日期的列)并调整一次大小,这让我认为循环本身有问题。非常感谢!
  • 赞成提供如此详细的答案
  • 即使我不认为我的回答特别详细,也谢谢你们。 ^^
【解决方案2】:

我在示例表上运行了代码,并注意了一些事项:

  1. .Cells(0,16) - 如 cmets 中所述 - 这实际上是您定义的行上方的行(在您的示例中,这将是第 18 行,E19:P19 上方的行),该单元格也将超过您的定义范围(在示例中为 T18)

  2. 如果最后一列(所有列不只是定义范围内的部分,例如 P1:P1048576)总和为 0,则代码将缩小

  3. 如果有一列的总和为 0,而另一列的总和为 0,则会发生奇怪的行为。在这种情况下,代码将缩小 1,但这将删除其中包含数据的列

  4. 如果没有列中有数据,那么您的代码将尝试将范围调整为 null,这将不起作用并且会引发错误。

    鉴于这些代码确实有效,您能否扩展您正在尝试做的事情以及“但它只循环一次并在第 11 个月停止”的意思,我们可以尝试帮助调整代码以适应您的使用

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-07
    相关资源
    最近更新 更多