通过功能提高效率,我迷失了

时间:2015-12-30 08:57:25

标签: vba excel-vba excel

我在与VBA斗争 - 我倾向于写作好像我是宏录制器,因此编写非常丑陋的宏并最终使事情变得比需要的复杂得多。

您是否可以查看并帮助确定一些效率?我想学习编写好的代码,但需要比较和对比,而不是看其他人的例子。

Sub ColumnSearch()
'Filepath variables - the filename changes daily but always contains the name notifications, this seemed to be the easiest method

Dim filepath As String
filepath = ActiveWorkbook.Path + "\"
Application.ScreenUpdating = False
Dim file As String
Dim fullfilepath As String
file = Dir$(filepath & "*Notifications*" & ".*")
fullfilepath = filepath & file
Application.EnableEvents = False
Workbooks.Open (fullfilepath)
Windows(file).Activate
Application.EnableEvents = True


'variables set as string and range respetively

Dim strDoN As String, strOffice As String, strARN As String, strPIN As String, strAN As String, strAT As String, strSoS As String
Dim rngDoN As Range, rngOffice As Range, rngARN As Range, rngPIN As Range, rngAN As Range, rngAT As Range, rngSoS As Range
Dim rng2DoN As Range, rng2Office As Range, rng2ARN As Range, rng2PIN As Range, rng2AN As Range, rng2AT As Range, rng2SoS As Range

Dim myRange As Range
Dim NumCols, i As Integer

'str variables set as the text in row 1 (title cells)
strDoN = "Date of Notification"
strOffice = "Office Centre"
strARN = "Appeal Reference Number"
strPIN = "PIN"
strAN = "Appellant Name"
strAT = "Appeal Type"
strSoS = "SoS Decision Date"

Sheets("New Appeals").Activate

'For loop to find the address of the strings above

For i = 1 To 11
    Select Case Cells(1, i).Value
        Case strDoN
            Set rngDoN = Cells(1, i)   '
        Case strOffice
            Set rngOffice = Cells(1, i)
        Case strARN
            Set rngARN = Cells(1, i)
        Case strPIN
            Set rngPIN = Cells(1, i)
        Case strAN
            Set rngAN = Cells(1, i)
        Case strAT
            Set rngAT = Cells(1, i)
        Case strSoS
            Set rngSoS = Cells(1, i)
        Case Else
            'no match - do nothing
    End Select
Next i

'Identify the count of cells to be copied from one sheet to the other
RowLast = Cells(Rows.Count, rngOffice.Column).End(xlUp).Row
Cells(RowLast - 1, rngOffice.Column).Select
Range(Selection, Selection.End(xlUp)).Offset(1, 0).Copy

'activate the other workbook, run the same search for loop but with rng2 being set (rng and rng2 can be different as there are sometimes extra columns that are not required
Workbooks("Book2.xlsm").Activate
Sheets("New Appeals").Select



For i = 1 To 11
    Select Case Cells(1, i).Value
        Case strDoN
            Set rng2DoN = Cells(1, i)   '<~~ set the range object to this cell
        Case strOffice
            Set rng2Office = Cells(1, i)
        Case strARN
            Set rng2ARN = Cells(1, i)
        Case strPIN
            Set rng2PIN = Cells(1, i)
        Case strAN
            Set rng2AN = Cells(1, i)
        Case strAT
            Set rng2AT = Cells(1, i)
        Case strSoS
            Set rng2SoS = Cells(1, i)
        Case Else
            'no match - do nothing
    End Select
Next i

Dim RowLast2 As Long

'find the last cell that was updated (every day the list will grow, it has to be pasted at the bottom of the last update)

RowLast2 = Cells(Rows.Count, rng2Office.Column).End(xlUp).Row
Cells(RowLast2, rng2Office.Column).Offset(1, 0).Select
Selection.PasteSpecial

Workbooks(file).Activate
Sheets("New Appeals").Select

'start from scratch again but with the next variable etc

RowLast = Cells(Rows.Count, rngARN.Column).End(xlUp).Row
Cells(RowLast - 1, rngARN.Column).Select
Range(Selection, Selection.End(xlUp)).Offset(1, 0).Copy
Workbooks("Book2.xlsm").Activate
Sheets("New Appeals").Select

RowLast2 = Cells(Rows.Count, rng2ARN.Column).End(xlUp).Row
Cells(RowLast2, rng2ARN.Column).Offset(1, 0).Select
Selection.PasteSpecial

Workbooks(file).Activate
Sheets("New Appeals").Select


End Sub

如果这是不适当的,请告诉我,如果需要,我会删除它!

1 个答案:

答案 0 :(得分:4)

我会考虑以下事项:

  • 宏描述:子程序标题下面的注释应简明扼要,并解释宏的作用,如果它的名称不清楚。您的子例程搜索列。您可能希望包括搜索的内容,即“搜索预定义的字符串集,选择[...]和[...]到[...]的副本。我会避免使用”这似乎是是最简单的方法“。
  • 表示法/变量名称:最好为变量指定一致的名称。在VBA CamelCase很常见。另外,在变量名中加上对象类型是很常见的,即strDoN as String。如果您这样做,请确保您无处不在(因此filepath应为strFilePath)。有关命名约定,请参阅here
  • 类型声明:将所有Dim语句放在子例程的开头。
  • 活动:请注意启用和停用活动。如果禁用事件,则不会自动重新启用它们,因此如果出现错误(例外),应该有其他操作重新启用事件。有关错误处理的详细信息,请参阅this post
  • 正如Chris Neilsen在评论中提到的,请避免使用SelectActivate
  • 正确Dim - ing :当您执行Dim NumCols, i as Integer时,实际上Dim NumCols as Variant, i as Integer。如果您希望它们都是整数,请使用Dim Numcols as Integer, i as Integer。此外,更喜欢LongInteger
  • 明确声明:将Option Explicit置于您的模块/工作表之上。这意味着应该首先声明使用的每个变量(使用Dim语句)。这对于避免来自拼写错误的错误以及将所有变量定义在一个位置非常有用。您的某些变量(例如RowLast)现在未明确定义,并且属于Variant类型,而其类型可能更具体。
  • 避免硬编码:最好不要明确引用用户在工作表中更改的内容。示例:如果工作表名称为Sheets("New Appeals").ActivateNew Appeals将起作用,但如果用户更改了名称,它将会中断。 Use the sheet's ID instead。同样,在您的代码中,您将字符串变量分配给硬编码字符串("Date of Notification"等)。如果您在工作表中设计一个区域,每次都可以从中提取数据,这样会更安全。
  • 处理大量Case s :最佳解决方案是使用Dictionary个对象。它更优雅,代码更简洁。一个例子是here
  • 复制和粘贴:使用Range.CopyRange.PasteSpecial方法代替Selection方法。此外,并不总是需要激活工作表以便复制/粘贴。 Range对象可以做有用的东西(搜索,特殊单元等)。 Check it out
  • 完全限定范围:从不同的工作表/文件复制粘贴数据时,请始终使用Range/Cells对象的全名,以避免错误。相关SO帖子here
  • 处理大范围:当数字变大时,在ExcelVBA之间传递数据可能非常耗时。一个好的做法是将excel数据传递给Variant数组,执行任何处理,然后将它们转储回excel。 This是一本很好的读物。
  • 使用With:当您多次引用对象的属性/方法时,它会增强可读性。示例here

我希望这会有所帮助。这并不是一个详尽的清单,但从一开始就可能有用。快乐的编码!