自动filter,然后xlcelltypevisibleselect空行

我是VBA和编程的新手。 我正在使用excel中的大型数据表 – 我的工作表通常有65K行。

我想要两列作为我的input,并有优秀的写公式输出到两个新的列。 我不需要为所有行执行此操作,所以我试图过滤我的数据,并将计算输出仅应用于剩余的可见单元格。 但是,我的代码似乎在底部添加了一堆额外的空白行(行计数为145K!),然后尝试计算这些行,从而导致macros挂起。

我如何解决这个范围select问题? 另外,有没有更好的方法来进行分类? 谢谢!

Sub CalcSpec() Dim s As Worksheet For Each s In ActiveWorkbook.Sheets If (Left(s.Name, 7) = "Channel" And Right(s.Name, 1) = "1") Then s.Activate UserMassInput.Show 1 'Sets up value in R2C21 referenced later 'Select only relevant data from cycles 1-5 With ActiveSheet .AutoFilterMode = False .Range("A1:Q1").AutoFilter .Range("A1:Q1").AutoFilter Field:=6, Criteria1:="<=5" .Range("A1:Q1").AutoFilter Field:=5, Criteria1:=Array("2", "3", "5"), Operator:=xlFilterValues End With 'Here's where I try and fail to select only the relevant range Dim cyCells As Range Set cyCells = Columns("R:S").SpecialCells(xlCellTypeVisible) 'Apply formula to calculate specific capacities For Each cell In cyCells cell.FormulaR1C1 = "=RC[-9]*1000/R2C21" Next cell 'Label all the new columns ActiveSheet.Range("R1").Value = "Spec CC" ActiveSheet.Range("S1").Value = "Spec DC" ActiveSheet.AutoFilterMode = False End If Next s End Sub 

它看起来不像你的代码添加任何东西到工作表,也许空行已经在那里,你只注意到他们,因为操作? 因为你在做:

.Range("A1:Q1").AutoFilter

Excel正在将该范围解释为该大小。 有多种方法可以在工作表或范围中查找“上次使用的行”。 试试这个方法:

http://www.siddharthrout.com/2012/10/02/find-last-row-in-an-excel-sheetvbavb-net/

一旦确定了最后使用的行,请更改自动筛选范围以明确定义要过滤的范围。

尝试这样的事情。 它在我的最后几乎在一个(很多)较小的工作表上使用了一些虚拟数据进行了全面的testing。

 Option Explicit Sub CalcSpec() Dim s As Worksheet Dim lRow As Long Dim filteredRange As Range Dim cl As Range Dim a As Range '## First, disable automatic calculation and screenupdating Application.ScreenUpdating = False Application.Calculation = -4135 'xlCalculationManual For Each s In ActiveWorkbook.Sheets '## I modified this logic to use a GoTo instead of putting everything inside an If Block If Not ((Left(s.Name, 7) = "Channel" And Right(s.Name, 1) = "1")) Then GoTo NextSheet UserMassInput.Show 1 'Sets up value in R2C21 referenced later 'Select only relevant data from cycles 1-5 With s '## Define our range using the LAST_ROW of the worksheet Set filteredRange = .Range("A1:Q" & LastRow(s)) .AutoFilterMode = False '## Apply autofilter Explicitly to the range defined above filteredRange.AutoFilter Field:=6, _ Criteria1:="<=5" filteredRange.AutoFilter Field:=5, _ Criteria1:=Array("2", "3", "5"), _ Operator:=xlFilterValues 'Here's where I try and fail to select only the relevant range Dim cyCells As Range Set cyCells = filteredRange.Resize(, 2).Offset(0, 17).SpecialCells(xlCellTypeVisible) 'Apply formula to calculate specific capacities '## I'm pretty sure you need to iterate the AREAS in a filtered range, ' and then the cells/rows within each AREA For Each a In cyCells.Areas For Each cl In a.Cells cl.FormulaR1C1 = "=RC[-9]*1000/R2C21" Next Next 'Label all the new columns .Range("R1").Value = "Spec CC" .Range("S1").Value = "Spec DC" .AutoFilterMode = False End With NextSheet: Next s '## Remember to turn screenupdating and calculation back ON Application.Calculation = -4105 'xlCalculationAutomatic Application.ScreenUpdating = True End Sub Function LastRow(Optional ws As Worksheet = Nothing) As Long If ws Is Nothing Then Set ws = ActiveSheet Dim r As Long r = ws.Range("A" & ws.Rows.Count).End(xlUp).Row LastRow = r End Function 

UPDATE

关于多重条件…我尽量避免使用GoTo语句 – 他们会感到困惑,随着时间的推移难以维护您的代码。 我在这种情况下使用它只是因为它真的出现了,你只是想忽略这些条件不符合的表。

对于每个条件和不同的操作,嵌套的If语句和/或使用Select Case语句通常是我喜欢的方式。 你可以这样做,而不是:

 For Each s In ActiveWorkbook.Sheets If Left(s.Name,7) = "Channel" Then Select Case Right(s.Name, 1) Case "%" ' ' ' Within this block you put your code ' to do opertations on sheets like Channel*% ' or, call an appropriate subroutine ' Case "1" ' ' Within this block you put your code ' do operations on sheets like Channel*1 ' or, call an appropriate subroutine ' ' ' NOTE: You can add as many Case statements _ ' as you need, BEFORE the "Case Else" Case Else ' do operations on other sheets, or ignore them ' ' ' End Select End If If Left(s.Name, 10) = "Statistics" Then Select Case Right(s.Name, 1) Case "%" Case "1" Case Else End Select End If Next