Vba 如果单元格不包含值,则删除行

Vba 如果单元格不包含值,则删除行,vba,excel,Vba,Excel,我希望传递O列中某个范围内的所有单元格,并删除所有不包含值的行:OI和SI 我的代码显示以下位置的错误: If Selection.Value <> "SI" Or "OI" Then 作为一种类型不匹配 Sub CHECK() Dim MFG_wb As Workbook Dim Dep As Integer Dim I As Integer Set MFG_wb = Workbooks.Open _ ("C:\Users\rosipov\Desktop\eliran\MFG

我希望传递O列中某个范围内的所有单元格,并删除所有不包含值的行:OI和SI

我的代码显示以下位置的错误:

If Selection.Value <> "SI" Or "OI" Then
作为一种类型不匹配

Sub CHECK()
Dim MFG_wb As Workbook
Dim Dep As Integer
Dim I As Integer

Set MFG_wb = Workbooks.Open _
("C:\Users\rosipov\Desktop\eliran\MFG - GSS\MFG Daily\Fast Daily " & Format(Now(), "ddmmyy") & ".xlsx", _
UpdateLinks:=False, IgnoreReadOnlyRecommended:=True)
MFG_wb.Sheets("Aleris").Activate

Dep = MFG_wb.Sheets("Aleris").Range("O2", Range("O2").End(xlDown)).Count

Range("O2").Select

For I = 1 To Dep

    If Selection.Value <> "SI" Or "OI" Then
        EntireRow.Delete
    Else
        Selection.Offset(1, 0).Select
    End If

Next I

End Sub

使用MFG_wb.SheetsAleris.Activate激活图纸后,无需显式将其用于范围对象。在上述行之后,代码应该如下所示:

Dim s As Sheet
Set s = MFG_wb.Sheets("Aleris")
'determine last row in O column
Dep = s.Cells(s.Rows.Count, 15).End(xlUp).Row

For I = 1 To Dep Step -1
    If InStr(1, s.Cells(I, 15).Value, "SI") + InStr(1, s.Cells(I, 15).Value, "OI") = 0  Then
        s.Cells(I, 15).EntireRow.Delete
    End If
Next I
您发布的代码发生更改的主要原因是您正在使用Select方法,这不是一个好的做法。若你们感兴趣的话,我建议你们读一读为什么你们应该避免使用这些功能。

只要修改一下就行了 如果选择值为SI或OI,则 到
如果Selection.Value SI或Selection.ValueOI,则如LUKLAG所述,从底部开始。另外,最好获取xlLastCell不在空白单元格停止计数行,并调整if语句以检查SI和OI:

Dep = MFG_wb.Sheets("Aleris").Range("O2").SpecialCells(xlLastCell).Row


For I = Dep To 2 Step -1
    Cells(I, 15).Select
    If Not (Selection.Value = "SI" Or Selection.Value = "OI") Then
        Rows(I).Delete
    End If
Next I

请尝试使用此代码来解决您的问题。它不仅修复了有问题的线路,而且还避免了其他一些从长远来看不可避免会导致问题的陷阱

Sub CHECK()
    Dim ManufacturingFile As Workbook
    Set ManufacturingFile = Workbooks.Open _
                 ("C:\Users\rosipov\Desktop\eliran\MFG - GSS\MFG Daily\Fast Daily " & Format(Now(), "ddmmyy") & ".xlsx", _
                  UpdateLinks:=False, IgnoreReadOnlyRecommended:=True)

    Dim Aleris As Worksheet
    Set Aleris = ManufacturingFile.Worksheets("Aleris")

    Dim TotalRows As Long
    TotalRows = Aleris.Range("O2", Aleris.Range("O2").End(xlDown)).Count

    ' Avoid Select at all costs
    ' Range("O2").Select

    Dim i As Long
    For i = TotalRows To 1 Step -1
        If Aleris.Range("O" & i).Value <> "SI" And Aleris.Range("O" & i).Value <> "OI" Then
            Aleris.Rows(i).Delete
        End If
    Next i
End Sub
首先,您的问题是由If Selection.Value SI或OI引起的,因为OI不能作为布尔语句计算。在幕后,口译员试图将OI转换为真或假,但未能成功。因此,您会得到一个错误。解决方法很简单:

如果选择.Value SI或选择.Value OI,则。现在我们有两个布尔语句,都在检查是否相等。口译员对此很满意,可以很好地运行

除此之外,我还修复了您不合格的范围引用,以及您的激活和选择实践。尽管其他人提出了一些建议,但这两个都是非常坏的习惯。你的代码将被破坏,这将使你付出代价。不相信我?阅读几乎所有其他关于激活和选择的帖子,你会看到同样的事情

为什么这是个坏主意?在运行时,您完全无法控制ActiveSheet是什么。当然,你可以激活它,但会有一段时间,有东西进来,改变焦点到另一张纸上,然后你会有问题。如果你不小心的话,这一个bug可能会花费数小时的工作时间

解决办法很简单。只需声明一个几乎所有的变量,然后使用该变量。瞧!不用再担心床单弄错了

最后,当您使用索引引用工作表的某些部分时,Excel非常善于理解您的意思。您不必先选择Selection.Offset1,0。然后选择Selection.EntireRow.Delete,因为这实际上意味着ActiveSheet.RowsSelection.Row+1.Delete,我们可以进一步重构它以使用工作表和Foo.Rowsi+1.Delete的索引。看到这里的图案了吗?一步一步地变得更加抽象,直到代码变得坚实

我最后更改的是变量名。使用描述性名称,可以使代码更易于维护。此外,在理解接口之前,永远不要在名称中使用下划线。下划线对口译员有特殊的意义

最后,查看Rubberduck项目:ruberduckvba.com。这是一个免费的插件,专门用于改善VBA编码体验。最好的部分是什么?这些反馈大多作为检查内置于研发中。它为你工作,你在这个过程中学习


祝你好运

单个删除行速度较慢。此删除行多次,因此删除时间较长 合并范围后,立即删除合并范围。使用Union方法

Sub CHECK()
Dim MFG_wb As Workbook
Dim Dep As Long
Dim i As Long '<~~  if your data is large then use long
Dim Ws As Worksheet
Dim s As String
Dim rngU As Range


    Set MFG_wb = Workbooks.Open _
    ("C:\Users\rosipov\Desktop\eliran\MFG - GSS\MFG Daily\Fast Daily " & Format(Now(), "ddmmyy") & ".xlsx", _
    UpdateLinks:=False, IgnoreReadOnlyRecommended:=True)
    'MFG_wb.Sheets("Aleris").Activate

    Set Ws = MFG_wb.Sheets("Aleris") '<~~ instead activate, use variable
    With Ws
        Dep = .Range("O2").End(xlDown).Row
    'Range("O2").Select '<~~ select mothod is not goo.
        For i = 2 To Dep
            s = .Range("o" & i)
            If s = "SI" Or s = "OI" Then
            Else
                If rngU Is Nothing Then
                    Set rngU = .Range("o" & i)
                Else
                    Set rngU = Union(rngU, .Range("o" & i))
                End If
            End If
        Next i
    End With
    If rngU Is Nothing Then
    Else
        rngU.EntireRow.Delete
    End If
MFG_wb.Save
MFG_wb.Close (0)
End Sub

添加更多信息:它如何不起作用?它会抛出一个错误,还是不做你想做的?另外,您使用的Office版本可能与@RealCheeseLord重复。它显示了一个错误:如果选择。值SI或OI,则作为类型不匹配删除行时,最佳做法是从底部开始,然后向上操作。这样你就不需要你的I=I-1。为此,将I=1到Dep更改为:I=1到Dep步骤-1最好完全避免激活,并保留对工作表的引用。您误解了我的意思,我想用SI或OI保留行,删除其他行。@RafaelOsipov,然后你的问题写得不够清楚。@MichałTurczyn使用Activate命令实际上是一种非常糟糕的做法,你建议Rafael使用不合格的范围和单元格引用,这使问题更加复杂。这是个糟糕的主意。最简单的例子是,如果在代码运行过程中激活了另一个工作表,该怎么办?提示:您不再使用您认为正在使用的工作表。您应该始终使用指向要使用的对象的变量来完全限定范围引用。非常好,谢谢!它完成了工作,但在几个循环之后,它停止并写入了range类的delete方法failedMaybe您的工作表包含一个带有标题的表,应该跳过它,我没有想到,如果是这样的话,只需返回到第二行:对于I=Dep到2步骤-1,还有关于best pract的注释
Brandon Barney的ICE非常有效,不使用selection、activate等。请确保在selection.ValueOI中添加间距。否则,你会发现。这就是应该引发以下错误的问题:。对于rngU.Entireow,范围类的Delete方法失败。Delete@RafaelOsipov,因为添加If rngU不是其他值,所以不应该失败。如果选择.Value SI或选择.Value OI,则将始终计算为True。如果.Value=OI,则默认情况下,.Value SI为真,反之亦然。它需要是If Selection.Value SI和Selection.Value OI Then。好的捕获。我知道这件事有点不对劲,但我没有想清楚。