复杂的多选案例,变量声明,范围定义

时间:2015-04-10 04:48:13

标签: excel vba excel-vba

我开发了以下代码,用于我从头开始创建的预算模板。目的是将实际GL数据信息自动填充到工作簿中的假设选项卡中。我使用一个特定月份作为测试。我已设置假设选项卡,以便有大约26个不同的区域办事处信息部分,以确定适当的预测。

并非所有GL都是逐项列出的。我已将GL用于特定费用(其他管理员)的类别。我有大约5种主要类别的花费,其余的GL被认为是"其他"。由于类别的标题与GL帐户的标题不完全相同,因此我必须在工作簿的单独选项卡上创建地图网格,以便将类别名称与不同的GL链接起来。

最终目标是:

  1. 在每个PM区域办事处的假设选项卡上循环浏览每个类别类型,
  2. 计算PM办公室及其他工作簿中的成本中心每笔支出(即驱逐)的总金额,
  3. 计算来自同一其他工作簿的每个实体代码项目的总金额。
  4. 以下代码仅循环并计算Eviction GL的支出。我希望改进性能改进代码,更轻松的未来维护(灵活性)和效率。最终目标是循环使用不同类型的支出。截至目前,我的解决方案是重复变量/范围声明,用EvictionRg代替下一次花费,以及添加另一个 case

    我担心代码会变得太长,性能可能会受到威胁。任何有关我如何计划,修改代码等的见解和指导,以帮助我这样做将不胜感激。通过实际绘制流程图和其他方法帮助我进行头脑风暴并阅读SO上的其他帖子,我已经在这三天试图找出它。我担心我的VBA知识结束了。

    Sub Try()
    'Application.Calculation = xlCalculationManual
    Application.ScreenUpdating = False
    
    Dim Wb1 As Workbook
    Dim Wb2 As Workbook
    
    Set Wb1 = Workbooks("SubModel Forecast_Other Admin v4.xlsm")
    Set Wb2 = Workbooks("Feb15 PNL.xlsx")
    
    Dim Wk4 As Worksheet
    Set Wk4 = Wb1.Sheets("ASSUMPTIONS")
    
    Dim Wk5 As Worksheet
    Set Wk5 = Wb1.Sheets("Validation")
    
    Dim Wk7 As Worksheet
    Set Wk7 = Wb1.Sheets("GL Mapping")
    
    Dim Wk1 As Worksheet
    Set Wk1 = Wb2.Sheets("det")
    
    Dim fname As String
    fname = "Feb15 PNL"
    
    With Wb1  '----submodel
        With Wk5 '---validation tab
            Dim CCCol As Long
            Dim fRowCC As Long
            Dim lRowCC As Long
            CCCol = Wk5.Cells.Find("Cost Center", lookat:=xlWhole).Column
            fRowCC = Wk5.Cells.Find("Cost Center", lookat:=xlWhole).Offset(1, 0).row
            lRowCC = Wk5.Cells.Find("Cost Center", lookat:=xlWhole).End(xlDown).row
            '---Determine cost center code column range and it's corresponding Region Office Name(ClinkRg)
            Dim CCRg As Range
            Set CCRg = Wk5.Range(Wk5.Cells(fRowCC, CCCol), Wk5.Cells(lRowCC, CCCol))
            Dim CLinkRg As Range
            Set CLinkRg = Wk5.Range(Wk5.Cells(fRowCC, CCCol).Offset(0, -1), Wk5.Cells(lRowCC, CCCol).Offset(0, -1))
        End With '----closes W5 Validation tab
    
        '----Grid that contains GL accounts and their category type
        With Wk7
            Dim MapGLCol As Long
            MapGLCol = Wk7.Cells.Find("GL", lookat:=xlWhole).Column
            Dim MapfRow As Long
            MapfRow = Wk7.Cells.Find("GL", lookat:=xlWhole).Offset(1, 0).row
            Dim MaplRow As Long
            MaplRow = Wk7.Cells(rows.Count, MapGLCol).End(xlUp).row
            Dim MapGLRg As Range
            Set MapGLRg = Wk7.Range(Wk7.Cells(MapfRow, MapGLCol), Wk7.Cells(MapfRow, MapGLCol))
            Dim TypeRg As Range
            Set TypeRg = Wk7.Range(Wk7.Cells(MapfRow, MapGLCol).Offset(0, -1), Wk7.Cells(MaplRow, MapGLCol).Offset(0, -1))
        End With '--closes wk7 - GL Mapping
    End With '--closes Wb1 - SubModel file
    
    '---------PNL wkb
    With Wb2
        With Wk1
    
            'If Left(Wk2.Name, 5) = "By PM" Then
                Dim OpsCol As Long
                OpsCol = Wk1.Cells.Find("Property Manager", lookat:=xlWhole).Column
            'Else
             '   OpsCol = Wk1.Cells.Find("Submarket", lookat:=xlWhole).Column
            'End If
    
            Dim FRow As Long
            Dim LRow As Long
            'Dim ExpCol As Long
            Dim PropCodeCol As Long
    
    
            'Dim Expense As String
            'Expense = InputBox("Enter Expense GL")
    
            'to locate begining and ending row of data on PNL report
            'Identifies the column where the SubMarket names are located for lookup purposes
            'Defines the expense GL column to lookup based on the inputbox above
            FRow = Wk1.Cells.Find("66990000", lookat:=xlPart).Offset(2, 0).row
            LRow = Wk1.Cells.Find("66990000", lookat:=xlPart).End(xlDown).Offset(-1, 0).row
            'ExpCol = Wk1.Cells.Find(Expense, lookat:=xlPart).Column
            PropCodeCol = Wk1.Cells.Find("Property Code", lookat:=xlWhole).Column
    
    
            'Defines the Range of the PM
            Dim OpsRg As Range
            Set OpsRg = Wk1.Range(Wk1.Cells(FRow, OpsCol), Wk1.Cells(LRow, OpsCol))
    
            'Defines the Range of the Property Codes
            Dim PropCodeRg As Range
            Set PropCodeRg = Wk1.Range(Wk1.Cells(FRow, PropCodeCol), Wk1.Cells(LRow, PropCodeCol))
    
            'Defines the exact range of the expense column being analyzed
            'Dim ExpRg As Range
            'Set ExpRg = Wk1.Range(Wk1.Cells(FRow, ExpCol), Wk1.Cells(LRow, ExpCol))
    
            'Defining range for GLs under Other Admin
            Dim GLRow As Long
            Dim BegGLCol As Long
            Dim EndGLCol As Long
            GLRow = Wk1.Cells.Find("66550000", lookat:=xlPart).row
            BegGLCol = Wk1.Cells.Find("66550000", lookat:=xlPart).Column
            EndGLCol = Wk1.Cells.Find("66990000", lookat:=xlPart).Column
    
            Dim GLRg As Range
            Set GLRg = Wk1.Range(Wk1.Cells(GLRow, BegGLCol), Wk1.Cells(GLRow, EndGLCol))
    
            '----Find All GL accounts in WB1 Wk5 Validation Tab range TypeRg categorized as Evictions($)
            '----Then Look up each GL account in the row with all the GLs in the current workbook PNL and Wk1
            '----------Set that up as TempCell
            '----------Set the range for the entire column of data for each GL and consolidate as one range 'EvictionRg'
            '----------Purpose of this is to set up one range for all GL accounts categorized as Eviction GL accoutns
            Dim c As Range
            For Each c In TypeRg
                If c = "Evictions ($)" Then
                    Dim TempCell As Range
                    Set TempCell = GLRg.Find(c.Offset(0, 1).Value, lookat:=xlWhole)
                    'MsgBox (TempCell)
    
                    Dim EvictionRg As Range
                    If EvictionRg Is Nothing Then
                        Set EvictionRg = Wk1.Range(Wk1.Cells(FRow, TempCell.Column), Wk1.Cells(LRow, TempCell.Column))
                    Else
                        Set EvictionRg = Union(EvictionRg, Wk1.Range(Wk1.Cells(FRow, TempCell.Column), Wk1.Cells(LRow, TempCell.Column)))
                    End If
    
                End If
            Next c
            '---Sum up all the amounts under all the GL eviction accounts and set them as "z"
            Dim z As Double
            z = Application.WorksheetFunction.Sum(EvictionRg)
    
        '---Define Ranges for All Entities, Cost Centers, Entities Not Cost Centers
    
        'Define the range on the Property PNL workbook all items booked under an entity
        Dim AllEntRg As Range
        Dim cell As Range
        For Each cell In OpsRg
          If cell = "" Then
              If AllEntRg Is Nothing Then
                  Set AllEntRg = Wk1.Cells(cell.row, PropCodeCol)
              Else
                  Set AllEntRg = Union(AllEntRg, Wk1.Cells(cell.row, PropCodeCol))
              End If
          End If
        Next cell
    
        'Define the range of the property PNL workbook that are Entity codes that are NOT Cost Center Codes
        '---Entity Codes and Cost Center Codes are within the AllEntRg
        '---Create a new range in the Eviction GL Range that intersects
        '---------the rows of the entity only codes and the eviction GL columns
        With AllEntRg
        Dim EntityRg As Range
        Dim cl As Range
        For Each cl In AllEntRg
                If CCRg.Find(cl.Value, lookat:=xlWhole) Is Nothing Then
                    Dim cl2 As Range
                    For Each cl2 In EvictionRg '------extra
                    If cl2.row = cl.row Then '------extra
                        If EntityRg Is Nothing Then
                            Set EntityRg = cl2
                        Else
                            Set EntityRg = Union(EntityRg, cl2)
                        End If
                    End If
                    Next cl2
                End If
        Next cl
        'MsgBox (EntityRg.Address)
        Dim v As Double
        v = Application.WorksheetFunction.Sum(EntityRg)
        End With
    
        'With AllEntRg
        'Dim CostCRg As Range
        'Dim r As Range
        'For Each r In AllEntRg
         '       If Not CCRg.Find(r.Value, lookat:=xlWhole) Is Nothing Then
         '           Dim cl3 As Range
         '           For Each cl3 In EvictionRg
         '           If cl3.row = r.row Then
         '               If CostCRg Is Nothing Then
         '                   Set CostCRg = cl3
         '               Else
         '                   Set CostCRg = Union(CostCRg, cl3)
         '               End If
         '           End If
          '          Next cl3
         '       End If
        'Next r
        'End With
        'MsgBox (CostCRg.Address)
    
        'Define cell ranges for regional PM offices that contain more than one cost center ocde
        With AllEntRg
            If Not AllEntRg.Find("cahied", lookat:=xlWhole) Is Nothing Then
                Dim n As Range
                Set n = AllEntRg.Find("cahied", lookat:=xlWhole)
            End If
            'MsgBox (n.Address)
    
            If Not AllEntRg.Find("cahrvr", lookat:=xlWhole) Is Nothing Then
                Dim n2 As Range
                Set n2 = AllEntRg.Find("cahrvr", lookat:=xlWhole)
                'MsgBox (n2.Address)
            End If
    
            If Not AllEntRg.Find("atlnw", lookat:=xlWhole) Is Nothing Then
                Dim an1 As Range
                Set an1 = AllEntRg.Find("atlnw", lookat:=xlWhole)
                'MsgBox (an1.Address)
            End If
    
            If Not AllEntRg.Find("atln", lookat:=xlWhole) Is Nothing Then
                Dim an2 As Range
                Set an2 = AllEntRg.Find("atln", lookat:=xlWhole)
                'MsgBox (an2.Address)
            End If
    
            If Not AllEntRg.Find("atlse", lookat:=xlWhole) Is Nothing Then
                Dim ae1 As Range
                Set ae1 = AllEntRg.Find("atlse", lookat:=xlWhole)
                'MsgBox (ae1.Address)
            End If
    
            If Not AllEntRg.Find("atle", lookat:=xlWhole) Is Nothing Then
                Dim ae2 As Range
                Set ae2 = AllEntRg.Find("atle", lookat:=xlWhole)
                'MsgBox (ae2.Address)
            End If
    
            If Not AllEntRg.Find("atlsw", lookat:=xlWhole) Is Nothing Then
                Dim as1 As Range
                Set as1 = AllEntRg.Find("atlsw", lookat:=xlWhole)
                'MsgBox (as1.Address)
            End If
    
            If Not AllEntRg.Find("atls", lookat:=xlWhole) Is Nothing Then
                Dim as2 As Range
                Set as2 = AllEntRg.Find("atls", lookat:=xlWhole)
                'MsgBox (as2.Address)
            End If
        End With
    
            '---Create a new range in the Eviction GL Range that intersects
            '---------the rows of the specific cost center codes and the eviction GL columns
            If Not n Is Nothing Or Not n2 Is Nothing Then
                Dim n3 As Range
                For Each n3 In EvictionRg
                   If n3.row = n.row Or n3.row = n2.row Then
                        Dim InlandRg As Range
                        If InlandRg Is Nothing Then
                            Set InlandRg = n3
                        Else
                            Set InlandRg = Union(InlandRg, n3)
                        End If
                    End If
                Next n3
            End If
                    Dim n3v As Double
                    n3v = Application.WorksheetFunction.Sum(InlandRg)
    
    
            If Not an1 Is Nothing Or Not an2 Is Nothing Then
                Dim an3 As Range
                For Each an3 In EvictionRg
                   If an3.row = an1.row Or an3.row = an2.row Then
                        Dim ATLNrg As Range
                        If ATLNrg Is Nothing Then
                            Set ATLNrg = an3
                        Else
                            Set ATLNrg = Union(ATLNrg, an3)
                        End If
                    End If
                Next an3
            End If
                    Dim an3v As Double
                    an3v = Application.WorksheetFunction.Sum(ATLNrg)
    
    
            If Not ae1 Is Nothing Or Not ae2 Is Nothing Then
                Dim ae3 As Range
                For Each ae3 In EvictionRg
                   If ae3.row = ae1.row Or ae3.row = ae2.row Then
                        Dim ATLErg As Range
                        If ATLErg Is Nothing Then
                            Set ATLErg = ae3
                        Else
                            Set ATLErg = Union(ATLErg, ae3)
                        End If
                    End If
                Next ae3
            End If
                    Dim ae3v As Double
                    ae3v = Application.WorksheetFunction.Sum(ATLErg)
    
            If Not as1 Is Nothing Or Not as2 Is Nothing Then
                Dim as3 As Range
                For Each as3 In EvictionRg
                   If as3.row = as1.row Or as3.row = as2.row Then
                        Dim ATLSrg As Range
                        If ATLSrg Is Nothing Then
                            Set ATLSrg = as3
                        Else
                            Set ATLSrg = Union(ATLSrg, as3)
                        End If
                    End If
                Next as3
            End If
                    Dim as3v As Double
                    as3v = Application.WorksheetFunction.Sum(ATLSrg)
    
        End With '---closes Wk1 (PNL report)
    End With '--closes wb2
    
    
    ''--------Cycle through the different PM regional office section (column) in assumptions tab
    '---------Identify where Evictions ($) is located
    '---------calculate total eviction GL amounts for each section (by Entity code only, by PM + cost center code)
    
    With Wb1
    With Wk4
    
        Wk4.Outline.ShowLevels RowLevels:=2
    
        Dim dateRow As Long
        dateRow = Wk4.Cells.Find("ACT", lookat:=xlWhole).Offset(1, 0).row
    
        Dim fRow2 As Long
        Dim AssumCol As Long
        Dim lRow2 As Long
        fRow2 = Wk4.Cells.Find("Global Assumptions", lookat:=xlWhole).row
        AssumCol = Wk4.Cells.Find("Global Assumptions", lookat:=xlWhole).Column
        lRow2 = Wk4.Cells(rows.Count, AssumCol).End(xlUp).row
    
        Dim AssumptionRg As Range
        Set AssumptionRg = Wk4.Range(Wk4.Cells(fRow2, AssumCol), Wk4.Cells(lRow2, AssumCol))
    
    
        Dim r2 As Range
        Dim isItem As Boolean
    
            For Each r2 In AssumptionRg
                Select Case r2
                    Case "Evictions ($)"
                        isItem = True
                        Dim PM As Range
                        Set PM = r2.End(xlUp)
                            '---If PM Label is Entity Level, Inland Empire or is one of the Atlanta PMs then
                            '-----IF Entity Level, the sum up the Entity Range for the Evictions
                            '-----IF Inland Empire, sum up Inland Empire properties and Inland Empire Cost Center entries
                            '-----IF Atlanta, the sum up Atlanta PMs and their cost center entries individually
                            If PM = "Tie-Out To Actuals" Or PM = "Entity Level Assumptions" _
                            Or PM = "Inland Empire" Or PM = "Atlanta East" _
                            Or PM = "Atlanta North" Or PM = "Atlanta South" Then
    
                                If PM = "Tie-Out To Actuals" Then
                                    Wk4.Cells(r2.row, 4) = z
                                End If
    
                                If PM = "Entity Level Assumptions" Then
                                    Wk4.Cells(r2.row, 4) = v
                                End If
    
                                If PM = "Inland Empire" Then
                                        Wk4.Cells(r2.row, 4).Formula = _
                                        "=SUMPRODUCT(('[" & fname & ".xlsx]det'!" & OpsRg.Address & "=" & PM.Address & ")*'[" & fname & ".xlsx]det'!" & EvictionRg.Address & ")" _
                                        & "+" & n3v
                                        Wk4.Cells(r2.row, 4).Value = Wk4.Cells(r2.row, 4).Value
                                End If
    
                                If PM = "Atlanta East" Then
                                    Wk4.Cells(r2.row, 4).Formula = _
                                    "=SUMPRODUCT(('[" & fname & ".xlsx]det'!" & OpsRg.Address & "=" & PM.Address & ")*'[" & fname & ".xlsx]det'!" & EvictionRg.Address & ")" _
                                    & "+" & ae3v
                                End If
    
                                If PM = "Atlanta North" Then
                                    Wk4.Cells(r2.row, 4).Formula = _
                                    "=SUMPRODUCT(('[" & fname & ".xlsx]det'!" & OpsRg.Address & "=" & PM.Address & ")*'[" & fname & ".xlsx]det'!" & EvictionRg.Address & ")" _
                                    & "+" & an3v
                                End If
    
                                If PM = "Atlanta South" Then
                                    Wk4.Cells(r2.row, 4).Formula = _
                                    "=SUMPRODUCT(('[" & fname & ".xlsx]det'!" & OpsRg.Address & "=" & PM.Address & ")*'[" & fname & ".xlsx]det'!" & EvictionRg.Address & ")" _
                                    & "+" & as3v
                                End If
    
                            Else
    
                                Dim CCCodeRow As Long
                                Dim CCCodeCol As Long
                                CCCodeRow = CLinkRg.Find(PM.Value, lookat:=xlWhole).Offset(0, 1).row
                                CCCodeCol = CLinkRg.Find(PM.Value, lookat:=xlWhole).Offset(0, 1).Column
    
                                If Wk5.Cells(CCCodeRow, CCCodeCol).Value = "None" Then
                                    Wk4.Cells(r2.row, 4).Formula = _
                                    "=SUMPRODUCT(('[" & fname & ".xlsx]det'!" & OpsRg.Address & "=" & PM.Address & ")*'[" & fname & ".xlsx]det'!" & EvictionRg.Address & ")"
                                Else
                                    Wk4.Cells(r2.row, 4).Formula = _
                                    "=SUMPRODUCT(('[" & fname & ".xlsx]det'!" & OpsRg.Address & "=" & PM.Address & ")*'[" & fname & ".xlsx]det'!" & EvictionRg.Address & ")" _
                                    & "+SUMPRODUCT(('[" & fname & ".xlsx]det'!" & PropCodeRg.Address & "=" & "Validation!" & Wk5.Cells(CCCodeRow, CCCodeCol).Address & ")*'[" & fname & ".xlsx]det'!" & EvictionRg.Address & ")"
                                End If
                            End If
               End Select
            Next r2
    
        Set r2 = Nothing
        Set Wk4 = Nothing
    End With '---closes assumptions tab
    End With '---workbook2
    'Application.Calculation = xlCalculationAutomatic
    Application.ScreenUpdating = True
    

2 个答案:

答案 0 :(得分:2)

哇,这是完全阅读!虽然我同意Comintern的观点,但我确实看到了一个非常简单的解决方案来修改代码并使其更易于维护。

我没有看到整个事情中的单一功能。如果你编写的脚本很长,而不是使用它们,你需要开始......它们会改变你的生活。

让我们看一个简单的块,我看到重复几(8)次。请注意,我看到几个更大的块在整个过程中重复出现,但这个块很容易学习。

If Not AllEntRg.Find("atlsw", lookat:=xlWhole) Is Nothing Then
    Dim as1 As Range
    Set as1 = AllEntRg.Find("atlsw", lookat:=xlWhole)
End If

我只看到三个因素从if到if在这部分代码中变化,输入端的2是范围和字符串,如果条件满足则输出范围。所以你编写一个这样的函数,并将它放在同一工作簿中的任何模块中。

Public Function DefMultiCCPMRange(rngSearchRange as range, strSearchString as string)as range
    If Not AllEndRg.Find(strSearchString, lookat:=xlWhole) Is Nothing Then
        set DefMultiCCPMRange = rngSearchRange.Find(strSearchString, Lookat:=xlWhole)
    End If
End Function

现在不要一遍又一遍地重写。

If Not AllEntRg.Find("atlsw", lookat:=xlWhole) Is Nothing Then
    Dim as1 As Range
    Set as1 = AllEntRg.Find("atlsw", lookat:=xlWhole)
End If

你一遍又一遍地写下这个。

Dim as1 as Range
set as1 = DefMultiCCPMRange(AllEndRg,"atlsw")

此外,函数中使用的变量的生命周期在函数结束时结束,因此您不会在运行的整个持续时间内存储在内存中使用的每个变量。

如果你玩它,这应该会让你走很长的路。

我还会研究数组,集合和字典项。一旦你看到他们的力量所在的位置,他们也会改变你的生活。您可以获得创意,而不是声明和设置该范围8次,您可以执行for循环,并将它们全部放在一个以CC代码命名的对象中。

Dim arrCCCodes(3) as string 'change to arrCCCodes(7) for your 8 codes
arrCCCodes(0) = "cahied"
arrCCCodes(1) = "cahrvr"
arrCCCodes(2) = "atlnw"
arrCCCodes(3) = "atln"
'etc...
'add a reference to Microsoft scripting runtime

Dim odicCCRanges as New Dictionary

For i = 0 to UBound(arrCCCodes)
    odicCCRanges.Add arrCCCodes(i), DefMultiCCPMRange(AllEndRg, arrCCCodes(i))
next

这将为您提供一个包含4个范围的字典对象(在您的实际代码中为8),更不用说丢失几页代码了。您可以调用odicCCRanges("cahied").Item(1)odicCCRanges(arrCCCodes(0)).Item(1)范围内的值。这是它增加项目生命周期的地方。如果你需要添加一个新的CC,你只需更改arrCCCodes声明以包含一个项目,然后在下面添加它,我们的其余代码将自动获取它,运行定义范围功能,并添加它到字典。

您的代码看起来并不那么糟糕,您对空值的测试,以及声明您的变量,都是好东西。这只是所有系列剧本。尝试单步执行代码,并在VBA IDE中查看本地窗口。特别是在设置之后扩展范围节点。它会让你大开眼界范围对象中的实际内容。

答案 1 :(得分:0)

你显然有很多时间投入这个,但我真的认为你已经过度复杂了。由于您的所有代码都在构建范围然后对它们求和,我认为您可以使用数组公式来完成此操作。