VBA代码删除不正确的行

VBA代码删除不正确的行,vba,excel,Vba,Excel,我有一段代码,如果一行在D列到L列中有空单元格,它将删除该行。 出于某种原因,它还删除了位于C8的我的标题单元格。 有人知道为什么吗?如何修复它 Sub RemoveEmptyRows() Dim ws As Worksheet For Each ws In Sheets ws.Activate Dim n As Long Dim nlast As Long Dim rw As Range Set rw = ActiveWorkbook.ActiveSheet.U

我有一段代码,如果一行在D列到L列中有空单元格,它将删除该行。
出于某种原因,它还删除了位于C8的我的标题单元格。
有人知道为什么吗?如何修复它

Sub RemoveEmptyRows()

Dim ws As Worksheet
For Each ws In Sheets
ws.Activate

  Dim n As Long
    Dim nlast As Long
    Dim rw As Range
    Set rw = ActiveWorkbook.ActiveSheet.UsedRange.Rows
    nlast = rw.count
    For n = nlast To 1 Step -1
        If (rw.Cells(n, 4).Value = "" And rw.Cells(n, 5).Value = "" And rw.Cells(n, 6).Value = "" And rw.Cells(n, 7).Value = "" And rw.Cells(n, 8).Value = "" And rw.Cells(n, 9).Value = "" And rw.Cells(n, 10).Value = "" And rw.Cells(n, 11).Value = "") Then
            rw.Rows(n).Delete
        End If
    Next n
    Next ws
End Sub

问题在于,您使用的是
UsedRange
的行和列索引,假设它们与
工作表的索引相匹配。事实并非如此。正如您在评论中向@YowE3K指出的,您有一些完全空的列

解决方案非常简单-只需使用
ws.Cells
而不是
rw.Cells
。我还将循环中的所有内容都放入带有
块的
中,以使其更快、更可读。您还可以通过将长
If
语句转换为
Select Case
梯形图来缩短该语句:

Sub RemoveEmptyRows()
    Dim ws As Worksheet
    For Each ws In ThisWorkbook.Sheets
        With ws
            Dim n As Long
            Dim nlast As Long
            nlast = .UsedRange.Rows(.UsedRange.Rows.Count).Row
            For n = nlast To 9 Step -1
                Select Case False
                    Case .Cells(n, 4).Value = vbNullString
                    Case .Cells(n, 5).Value = vbNullString
                    Case .Cells(n, 6).Value = vbNullString
                    Case .Cells(n, 7).Value = vbNullString
                    Case .Cells(n, 8).Value = vbNullString
                    Case .Cells(n, 9).Value = vbNullString
                    Case .Cells(n, 10).Value = vbNullString
                    Case .Cells(n, 11).Value = vbNullString
                    Case Else
                        .Rows(n).Delete
                End Select
            Next n
        End With
    Next ws
End Sub

请注意,还有更可靠的方法可以找到工作表的最后一行。

问题在于,您使用的是
UsedRange
的行和列索引,假设它们与
工作表的索引匹配。事实并非如此。正如您在评论中向@YowE3K指出的,您有一些完全空的列

解决方案非常简单-只需使用
ws.Cells
而不是
rw.Cells
。我还将循环中的所有内容都放入带有
块的
中,以使其更快、更可读。您还可以通过将长
If
语句转换为
Select Case
梯形图来缩短该语句:

Sub RemoveEmptyRows()
    Dim ws As Worksheet
    For Each ws In ThisWorkbook.Sheets
        With ws
            Dim n As Long
            Dim nlast As Long
            nlast = .UsedRange.Rows(.UsedRange.Rows.Count).Row
            For n = nlast To 9 Step -1
                Select Case False
                    Case .Cells(n, 4).Value = vbNullString
                    Case .Cells(n, 5).Value = vbNullString
                    Case .Cells(n, 6).Value = vbNullString
                    Case .Cells(n, 7).Value = vbNullString
                    Case .Cells(n, 8).Value = vbNullString
                    Case .Cells(n, 9).Value = vbNullString
                    Case .Cells(n, 10).Value = vbNullString
                    Case .Cells(n, 11).Value = vbNullString
                    Case Else
                        .Rows(n).Delete
                End Select
            Next n
        End With
    Next ws
End Sub

请注意,还有更可靠的方法可以找到工作表的最后一行。

以下是您的代码,稍作修改

Sub RemoveEmptyRows()

    Dim ws As Worksheet
    Dim n As Long
    Dim nlast As Long
    Dim rw As Range

    For Each ws In Worksheets 'changed. In case there are Chart Sheets.
    'deleted ws.activate. AVOID THAT AS PLAGUE
        Set rw = ws.UsedRange.Rows
        With rw
            nlast = .Count
            For n = nlast To 2 Step -1 'Note the 2, to skip title row. As was pointed in comments.
                If (.Cells(n, 4).Value2 = "" And .Cells(n, 5).Value2 = "" And .Cells(n, 6).Value2 = "" And .Cells(n, 7).Value2 = "" And .Cells(n, 8).Value2 = "" And .Cells(n, 9).Value2 = "" And .Cells(n, 10).Value2 = "" And .Cells(n, 11).Value2 = "") Then
                    .Rows(n).Delete
                End If
            Next n
        End With 'rw
    Next ws
End Sub

这是你的代码稍微修改一下

Sub RemoveEmptyRows()

    Dim ws As Worksheet
    Dim n As Long
    Dim nlast As Long
    Dim rw As Range

    For Each ws In Worksheets 'changed. In case there are Chart Sheets.
    'deleted ws.activate. AVOID THAT AS PLAGUE
        Set rw = ws.UsedRange.Rows
        With rw
            nlast = .Count
            For n = nlast To 2 Step -1 'Note the 2, to skip title row. As was pointed in comments.
                If (.Cells(n, 4).Value2 = "" And .Cells(n, 5).Value2 = "" And .Cells(n, 6).Value2 = "" And .Cells(n, 7).Value2 = "" And .Cells(n, 8).Value2 = "" And .Cells(n, 9).Value2 = "" And .Cells(n, 10).Value2 = "" And .Cells(n, 11).Value2 = "") Then
                    .Rows(n).Delete
                End If
            Next n
        End With 'rw
    Next ws
End Sub

您的标题在C8中,然后在第1行之前不要删除:

替换

For n = nlast To 1 Step -1


您的标题在C8中,然后在第1行之前不要删除:

替换

For n = nlast To 1 Step -1

您可以尝试以下(未测试)代码:

您可以尝试以下(未测试)代码:


如果顶部有空行,
UsedRange
的行索引不一定与工作表的行索引匹配。嗯,代码有点乱。例如,在循环中定义变量让我感到恶心。但实际上它删除了从第4(D)列到第11(K)列中没有任何内容的每一整行。因此,如果D8:K8中的单元格为空,第8行将被删除。尝试用F8单步遍历代码。我认为@Comintern的注释可能是原因,但您总是使用行作为从
UsedRange
开始的偏移量-实际上,您没有从
UsedRange
开始偏移的是列。我敢打赌,a、B或C列中都有一个完全空的列,因此
rw。单元格(n,4)
不是指D列(等)您是否只需要将For loop更新为
For n=nlast到第2步-1
,因为页眉正在
UsedRange
中计数?您的
UsedRange
的示例是什么?如果顶部有空行,
UsedRange
的行索引不一定与工作表的行索引匹配。嗯,代码有点乱。例如,在循环中定义变量让我感到恶心。但实际上它删除了从第4(D)列到第11(K)列中没有任何内容的每一整行。因此,如果D8:K8中的单元格为空,第8行将被删除。尝试用F8单步遍历代码。我认为@Comintern的注释可能是原因,但您总是使用行作为从
UsedRange
开始的偏移量-实际上,您没有从
UsedRange
开始偏移的是列。我敢打赌,a、B或C列中都有一个完全空的列,因此
rw。单元格(n,4)
不是指D列(等)您是否只需要将For loop更新为
For n=nlast至2 step-1
,因为标头正在
UsedRange
中计数?您的
UsedRange
示例是什么?@MTBthePRO-Yup。已修复。
对于n=nlast至9步骤-1
@MTBthePRO-Yup。已修复。
对于n=nlast至9步骤-1