设置一个范围以使macros在工作表中的所有填充行上运行

我拼凑了一个macros,让我通过计算基于开发人员的特定比率来计算故事任务的成本。 我在第二张纸上有费率表。 我能够得到一个macros设置为(第2行)的单元格的结果,但希望它在所有行上运行。 我知道我必须设定一个通用的范围,但我不确定。 我应该如何改变范围声明在所有行上运行?
这里是代码:

Sub GetCost() Range("D2").Select ' Set Do loop to stop when an empty cell is reached. Do Until IsEmpty(ActiveCell) Dim Estimate As Integer, Assignee As String, RodRate As Integer, GarthRate As Integer, DerekRate As Integer, TotalCost As Integer Estimate = ThisWorkbook.Worksheets("Sheet1").Range("D2").Value Assignee = ThisWorkbook.Worksheets("Sheet1").Range("E2").Value RodRate = ThisWorkbook.Worksheets("Sheet2").Range("B2").Value GarthRate = ThisWorkbook.Worksheets("Sheet2").Range("B3").Value DerekRate = ThisWorkbook.Worksheets("Sheet2").Range("B4").Value If Assignee = "Rod" Then TotalCost = Estimate * RodRate ElseIf Assignee = "Garth" Then TotalCost = Estimate * GarthRate ElseIf Assignee = "Derek" Then TotalCost = Estimate * DerekRate Else TotalCost = "0" End If ThisWorkbook.Worksheets("Sheet1").Range("F2").Formula = TotalCost ActiveCell.Offset(1, 0).Select Loop End Sub 

我已经重写了您的代码,我希望这些解释足以让您理解为什么。 还有更多我可以说的。 我希望这是一个太less和太多的好平衡。

但是,我必须指出,有一些优秀的项目pipe理工具可用。 我不相信这是一个很好的利用你的时间。

随机点

在32位计算机上,Long比Integer要好。

不要在循环中声明你的variables。 在子例程中声明的variables的作用域是子例程,所以在子例程的顶部声明它们。

你可以在一个Dim语句中声明所有的variables,但是除非两个或多个variables之间存在真正的关联, 我可能有:

 Dim RodRate As Long, GarthRate As Long, DerekRate As Long 

因为这些variables是相关的。 然而,这种方法的麻烦是,当这些人join你的项目时,你将不得不添加MaryRateJohnRateAngelaRate

你需要一个数组:

 Dim PersonRate(1 To 3) As Long 

PersonRate(1) = Rod, PersonRate(2) = Garth和PersonRate(3) = Derek的费率。

但这几乎没有更好的。 你想要一张可以增长的桌子。 所以今天:

  Name Rate Rod 20 Garth 25 Derek 15 

下周:

  Name Rate Rod 20 Garth 25 Derek 15 Mary 30 

有了这个,你拿起受让人的名字,跑下来,直到你find他们的名字,然后看看他们的速度。

我假设你在Sheet2中有这样的表格。 您可以继续回到Sheet2,但更好的是将表加载到数组中。

我们可以有:

 Dim PersonName() As String Dim PersonRate() As Long 

所以PersonRate(2)给出PersonName(2)的费率。

请注意在我写的第一个数组声明: PersonRate(1 To 3) 。 这一次,括号是空的。 PersonRate(1 To 3) ,我说我想正好在数组中的三个条目,这是不能改变的。 与PersonRate() ,我说我想要一个数组,但我不知道有多less条目,直到运行时。

我说我们可以有两个数组, PersonName()PersonRate() ,这就是我所做的。 这是一个容易理解的方法,但我不认为这是最好的方法。 我更喜欢结构。 当你有这个macros的工作,并开始你的下一个查找结构的VBA名称的User Types之前。

考虑:

  With Sheets("Sheet2") RowMax = .Cells(Rows.Count, "A").End(xlUp).Row End With 

这里有很多解释。

Cells意味着我要在活动工作簿中寻址单元格。 .Cells表示我想要处理With语句中标识的表单中的一个单元格。 这意味着我不必selectSheet1或Sheet2来查看其内容。 select工作表很慢,代码往往更难以理解。

.Cells(Row, Column)标识一个单元格。 行必须是数字,但列可以是数字或列代码:A = 1,B = 2,Z = 26,AA = 27等

Rows.Count返回您正在使用的Excel版本的工作表中的行数。 所以.Cells(Rows.Count, "A")标识列“A”的底部。

End(xlUp)是单击Ctrl + End(xlUp)的VBA等效项。 如果你不熟悉Ctrl + Arrow我build议你玩这四个控件。 请注意,这些控件使用矩形表格可以轻松理解结果。 但是,如果有空单元格,结果可能会很奇怪。

把它们放在一起: .Cells(Rows.Count, "A").End(xlUp).Row表示从列A的底部开始,直到你用一个值命中一个单元格并返回它的行号。 因此,将RowMax设置为Rate表的最后一行。 当你用玛丽的名字和费率添加第5行时,这段代码会自动调整。

修改后的代码

这应该足以让你开始。 欢迎来到编程的乐趣。

 ' * Require all variables to be declared which means a misspelt name ' is not taken as an implicit declaration Option Explicit Sub GetCost() Dim Estimate As Integer Dim Assignee As String Dim TotalCost As Integer Dim PersonName() As String Dim PersonRate() As String Dim InxPerson As Long Dim RowCrnt As Long Dim RowMax As Long ' You can declare constants and use them in place of literals. ' You will see why later. I could have made these strings and ' used "A", "B", "D", "E" and "F" as the values. Change if that ' is easier for you. Const ColS2Name As Long = 1 Const ColS2Rate As Long = 2 Const ColS1Estimate As Long = 4 Const ColS1Assignee As Long = 5 Const ColS1Total As Long = 6 ' Before doing anything else we must load PersonName and PersonRate from ' Sheet2. I assume the structure of Sheet2 is: ' AB ' 1 Name Rate ' 2 Rod 20 ' 3 Garth 25 ' 4 Derek 15 With Sheets("Sheet2") RowMax = .Cells(Rows.Count, ColS2Name).End(xlUp).Row ' I now know how big I want the the name and rate arrays to be ReDim PersonName(1 To RowMax - 1) ReDim PersonRate(1 To RowMax - 1) ' Load these arrays For RowCrnt = 2 To RowMax ' I could have used 1 and 2 or "A" and "B" for the column ' but this is easier to understand particularly if you come ' back to this macro in six month's time. PersonName(RowCrnt - 1) = .Cells(RowCrnt, ColS2Name).Value PersonRate(RowCrnt - 1) = .Cells(RowCrnt, ColS2Rate).Value Next End With With Sheets("Sheet1") ' I am using the same variable for rows in sheets Sheet1 and Sheet2. ' This is OK because I never look at Sheet1 and Sheet2 at the same time. RowCrnt = 2 Do Until IsEmpty(.Cells(RowCrnt, ColS1Estimate)) Estimate = .Cells(RowCrnt, ColS1Estimate).Value Assignee = .Cells(RowCrnt, ColS1Assignee).Value .Cells(RowCrnt, ColS1Total).Value = 0 ' Locate the Assignee in the PersonName array and ' extract the matching rate For InxPerson = 1 To UBound(PersonName) If PersonName(InxPerson) = Assignee Then .Cells(RowCrnt, ColS1Total).Value = Estimate * PersonRate(InxPerson) Exit For End If Next RowCrnt = RowCrnt + 1 Loop End With End Sub 

托尼的答案是一个很好的解决scheme和编程介绍,写得很好,所以我已经+1了。 但是,除非我错过了一些代码应该永远是最后的手段在Excel中,因为它是非常缓慢的公式,我会认为,一个简单的查找就足够了,像这样:

 =D2*(vlookup(E2,'sheet2'!A:B,2,FALSE)) 

复制下来的列