我想传递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
答案 0 :(得分:5)
尝试使用此代码来解决您的问题。它不仅修复了有问题的界限,而且避免了其他一些陷阱,从长远来看也不可避免地会引发问题。
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" Or "OI" Then
引起的,因为"OI"
无法作为Boolean
语句进行评估。在幕后,口译员试图将"OI"
转换为True
或False
,但无法将其转换为If Selection.Value <> "SI" or Selection.Value <> "OI" Then
。结果,您收到错误。修复很简单:
Boolean
。现在我们有两个Activate
语句,都检查是否相等。口译员对此很满意,并且运行得很好。
除此之外,我修复了您的不合格范围参考,以及Select
和Activate
的练习。尽管其他人提出了一些建议,但这些都是非常坏习惯。您的代码将中断,而 会花费您的代价。别相信我?几乎阅读关于Select
和ActiveSheet
的任何其他帖子,您会看到同样的事情。
为什么这是一个坏主意?您无法控制Activate
在运行时的状态。当然你可以Excel
它,但是会有一些时间进入并将焦点转移到另一张纸上,然后你就会遇到问题。如果您不小心,这一个错误可能会花费数小时的工作量。
修复很简单。只需声明一个变量(就像你几乎拥有的那样),并使用该变量。瞧!不再担心错误的表格。
最后,当您使用索引引用工作表的某些部分时,Selection.Offset(1, 0).Select
非常擅长理解您的意思。您不必Selection.EntireRow.Delete
然后ActiveSheet.Rows(Selection.Row + 1).Delete
,因为所有这些真正意味着Foo.Rows(i + 1).Delete
,我们可以进一步重构以使用工作表和{{1}的索引}。看到这里的模式?逐步变得更抽象,直到你的代码变得稳固。
我改变的最后一件事是你的变量名。使用描述性名称,它使您的代码更易于维护。此外,永远不会使用下划线&#34; _&#34;直到你理解Interfaces
为止。下划线对翻译有特殊意义。
最后,查看Rubberduck项目:rubberduckvba.com。它是一个免费的插件,致力于改善VBA编码体验。最好的部分?大部分反馈都作为检查内置于RD中。它为你工作,你可以在这个过程中学习。
祝你好运!
答案 1 :(得分:3)
正如Luuklag所说,从底部开始。最好还是获取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
答案 2 :(得分:2)
单个删除行很慢。(此删除行多次,因此需要很长时间才能删除) 合并范围后,立即删除合并范围。(使用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
答案 3 :(得分:1)
使用MFG_wb.Sheets("Aleris").Activate
激活工作表后,您无需明确将其与Range
个对象一起使用。在提到的行之后,代码应如下所示:
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
方法,这不是一个好习惯。如果您有兴趣,我建议您阅读为什么您应该避免使用这些功能。
答案 4 :(得分:1)
只需修理线路
If Selection.Value <> "SI" Or "OI" Then
为了
If Selection.Value <> "SI" Or Selection.Value<>"OI" Then