【问题标题】:Delete Rows if Cell Does not equal to Zero or Blank如果单元格不等于零或空白,则删除行
【发布时间】:2021-07-07 04:02:42
【问题描述】:

我研究了几个代码,但它要么只用于空白,要么只用于零,我需要一个用于空白和零的代码。

我有 3 列要注意是否应该删除它

我需要删除包含完整详细信息(ID 和地址)的行(名称是详细信息的基础),因为我需要保留不完整详细信息(ID 或地址为零或空白)的行。

ID        Name        Address        
1         A           123 ABC
2         B           0
          C           345 CDE
          D           
5         E           567 EFG
0         F           678 FGH
7         G           789 GHI
0         H           0

我的第一次尝试是这段代码,它适用于条件,但如果我有连续的空白,它会跳过下一行,因为该行上升

lrow = 1000
For x = 2 To lrow
If Cells(x,2)<>"" Then
If Cells(x,1) <> "" Or Cells(x,1) <> "0" Or Cells(x,3) <> "" Or Cells(x,3) <> "0" Then
Cells(x,11).EntireRow.Delete
End If
End If    
Next x

所以我尝试了这段代码,我从下到上开始。

lrow = 1000
For x = lrow To 2 Step -1
If Cells(x,2)<>"" Then
If Cells(x,1) <> "" Or Cells(x,1) <> "0" Or Cells(x,3) <> "" Or Cells(x,3) <> "0" Then
Cells(x,11).EntireRow.Delete
End If
End If    
Next x

但是该代码忽略了除第一个之外的条件,然后还删除了其他不完整的行。

我有点坚持这一点,因为我还必须创建另一个我做相反的事情,保留完整的细节,并删除不完整的细节。

【问题讨论】:

    标签: excel vba delete-row


    【解决方案1】:

    删除有条件的行

    向后循环

    Sub testSimple()
        Const lrow As Long = 1000
        Dim x As Long
        For x = lrow To 2 Step -1
            If Len(Cells(x, 1)) > 0 And Cells(x, 1) <> 0 Then
                If Len(Cells(x, 3)) > 0 And Cells(x, 3) <> 0 Then
                    Rows(x).Delete
                End If
            End If
        Next x
    End Sub
    

    编辑:

    该节目的明星是 If 语句,理想情况下(最有效)实际上应该是:

    If Len(Cells(x, 1)) > 0 Then
        If Cells(x, 1) <> 0 Then
            If Len(Cells(x, 3)) > 0 
                If Cells(x, 3) <> 0 Then
                    Rows(x).Delete
                End If 
            End If
        End If
    End If
    

    所有四个条件都必须为真。如果一个不是,则不会评估其他的。

    另一方面,你可以这样写

    If Len(Cells(x, 1)) > 0 And Cells(x, 1) <> 0 _
            And Len(Cells(x, 3)) > 0 And Cells(x, 3) <> 0 Then
        Rows(x).Delete
    End If
    

    ...不同之处在于后者(效率较低)会评估所有四个条件,即使第一个条件已经为假。

    相反,您可以使用相同的条件并执行以下操作(注意Else):

    If Len(Cells(x, 1)) > 0 And Cells(x, 1) <> 0 _
            And Len(Cells(x, 3)) > 0 And Cells(x, 3) <> 0 Then
        ' Do nothing
    Else        
        Rows(x).Delete
    End If
    

    让我们用Or重写相反的:

    If Len(Cells(x, 1)) = 0 Or Cells(x, 1) = 0 _
            Or Len(Cells(x, 3)) = 0 Or Cells(x, 3) = 0 Then
        Rows(x).Delete
    End If
    

    与“相反的想法”非常相似,您可以像这样编写初始语句(注意Else):

    If Len(Cells(x, 1)) = 0 Or Cells(x, 1) = 0 _
            Or Len(Cells(x, 3)) = 0 Or Cells(x, 3) = 0 Then
        ' Do nothing
    Else
        Rows(x).Delete
    End If
    

    结局(对面)

    使用Select Case 语句,您可以这样写相反的:

    Sub testSimple()
        Const lrow As Long = 1000
        Dim x As Long
        For x = lrow To 2 Step -1
            Select Case True
            Case Len(Cells(x, 1)) = 0, Cells(x, 1) = 0, _
                    Len(Cells(x, 3)) = 0, Cells(x, 3) = 0
                Rows(x).Delete
            End Select
        Next x
    End Sub
    

    ...其中逗号'意思是Or',所以如果任何表达式为真,行将被删除。

    旧(续):

    使用CombinedRange函数一次性删除

    Sub test()
        Const lrow As Long = 1000
        Dim drg As Range
        Dim x As Long
        For x = 2 To lrow
            If Len(Cells(x, 1)) > 0 And Cells(x, 1) <> 0 Then
                If Len(Cells(x, 3)) > 0 And Cells(x, 3) <> 0 Then
                    Set drg = CombinedRange(drg, Rows(x))
                End If
            End If
        Next x
        If Not drg Is Nothing Then
            drg.Delete
        End If
    End Sub
    

    使用改进的CombinedRange函数一次性删除

    Sub testImp()
        
        Const Cols As String = "A:C"
        Const fRow As Long = 2
        
        Dim rg As Range
        With Columns(Cols).Rows(fRow)
            Set rg = .Resize(.Worksheet.Rows.Count - .Row + 1) _
                .Find("*", , xlFormulas, , , xlPrevious)
            If rg Is Nothing Then Exit Sub
            Set rg = .Resize(rg.Row - .Row + 1)
        End With
        
        Dim drg As Range
        Dim rrg As Range
        For Each rrg In rg.Rows
            If Len(rrg.Cells(1)) > 0 And rrg.Cells(1) <> 0 Then
                If Len(rrg.Cells(3)) > 0 And rrg.Cells(3) <> 0 Then
                    Set drg = CombinedRange(drg, rrg.EntireRow)
                End If
            End If
        Next rrg
        
        If Not drg Is Nothing Then
            drg.Delete
        End If
    
    End Sub
    

    CombinedRange 函数

    Function CombinedRange( _
        ByVal BuildRange As Range, _
        ByVal AddRange As Range) _
    As Range
        If BuildRange Is Nothing Then
            Set CombinedRange = AddRange
        Else
            Set CombinedRange = Union(BuildRange, AddRange)
        End If
    End Function
    

    【讨论】:

    • 老实说,我不明白这大约 50%,但我还是会尝试并理解。
    • 我尝试了您发送的第一个代码,即向后循环的代码,它可以工作。如果我想要相反的反映,我该如何改变它?空白和零将被删除,而其余的则保留?
    • 如果你认为这个解决方案是一大堆Ands,那么相反的就是一大堆Ors,就像你在代码中所做的那样。此外,条件必须相反:If Len(Cells(x, 1)) = 0 Or Cells(x, 1) = 0 Or Len(Cells(x, 3)) = 0 Or Cells(x, 3) = 0 Then
    • 我试过了,但它只删除了零,而不是空白。
    • 你有没有像评论里那样把它放在一行里?只有一个If
    【解决方案2】:

    将 for 循环替换为 do while 循环。如果该行被删除,则减少总行数,否则增加行计数器。

    lastRow = 1000
    row = 2
    Do While row <= lastRow
        If Cells(row,1)<>"" Then
            If Cells(row,1) <> "" Or Cells(row,1) <> "0" Or Cells(row,3) <> "" Or Cells(row,3) <> "0" Then
                Rows(row).Delete
                lastRow = lastRow - 1
            else
                row = row + 1
            End If
        End If    
    Loop
    

    【讨论】:

    • 我试过你的代码,但它仍然会删除那些代码上有空白或零的代码。我在上面编辑了我的试用代码,因为第一个条件应该在第 2 列。
    猜你喜欢
    • 1970-01-01
    • 2019-06-18
    • 2015-11-13
    • 1970-01-01
    • 2022-01-23
    • 2022-11-24
    • 1970-01-01
    • 1970-01-01
    • 2018-04-15
    相关资源
    最近更新 更多