VBA Loop through rows but fails to exclude previous row contents - vba

I have the following Loop which dispatches email for every used row in the worksheet starting from the second row.
The loop itself works and it dispatches email for every used row starting from the second row.
However, my loop fails to exclude the previous row contents and accumulate them in the each of the next rows' emails. I suspect it is to do with my cell referencing. Would be great if you can help with this :).
Sub TestEmail1()
Application.ScreenUpdating = False
Dim aOutlook As Object
Dim aEmail As Object
Dim rngeAddresses As Range, rngeCell As Range, strRecipients As String
Dim ccAddresses As Range, ccCell As Range, ccRecipients As String
Dim rngeSubject As Range, SubjectCell As Range, SubjectContent As Variant
Dim rngeBody As Range, bodyCell As Range, bodyContent As Variant
Dim Table1 As Range
Dim i As Integer
Set rng = ActiveSheet.UsedRange
LRow = rng.Rows.Count
For i = 2 To LRow
Set Table1 = Worksheets(1).Range("K1:R1")
Set Table2 = Worksheets(2).Range("K" & i & ":" & "R" & i)
Set aOutlook = CreateObject("Outlook.Application")
Set aEmail = aOutlook.CreateItem(0)
'set sheet to find address for e-mails as I have several people to
'mail to
Set rngeAddresses = ActiveSheet.Range("B" & i)
For Each rngeCell In rngeAddresses.Cells
strRecipients = strRecipients & ";" & rngeCell.Value
Next
Set ccAddresses = ActiveSheet.Range("C" & i)
For Each ccCell In ccAddresses.Cells
ccRecipients = ccRecipients & ";" & ccCell.Value
Next
Set rngeSubject = ActiveSheet.Range("D" & i)
For Each SubjectCell In rngeSubject.Cells
SubjectContent = SubjectContent & SubjectCell.Value
Next
Set rngeBody = ActiveSheet.Range("E" & i)
For Each bodyCell In rngeBody.Cells
bodyContent = bodyContent & bodyCell.Value
Next
'set Importance
'aEmail.Importance = 2
'Set Subject
aEmail.Subject = rngeSubject
'Set Body for mail
'aEmail.Body = bodyContent
aEmail.HTMLBody = bodyContent & "<br><br><br>" & RangetoHTML_ (Table1)
aEmail.To = strRecipients
aEmail.CC = ccRecipients
aEmail.Send
Next i
Exit Sub
End Sub

Yes, you are accumulating longer and longer strings in SubjectContent, bodyContent and the other similar variables. Each time you pass through the For i = 2 to lRow loop you add the value of the specified cell in the current row to the associated Content variable.
For some reason you've also got an inner loop for each email area, e.g, For Each bodyCell in rgneBody.Cells. If I'm reading your code correctly none of those loops are needed.
So, taking into account the above, I would change:
Set rngeBody = ActiveSheet.Range("E" & i)
For Each bodyCell In rngeBody.Cells
bodyContent = bodyContent & bodyCell.Value
Next
to:
bodyContent = ActiveSheet.Range("E" & i)
You can use the intermediate rngeBody variable if you think it's more readable, but it's not necesssary.
Repeat the above for your other email area variables.

Related

Vba search and paste solution

i would like to come up with vba sub that searching value from one specified cell (job) across all sheets and then pastes rows but only with selected columns. If value not found any error message instead paste value.
I know it's bigger project but I'm fresh so try to my best.
As far i have solution for whole rows:
Sub TEST()
Dim tws As String
Dim l_row As String
Dim l_rowR As String
Dim job As String
Dim i As Integer
Set tws = ThisWorkbook.Sheets("Data")
tws.Range("A20") = "STATS:"
job = tws.Range("B5")
lastRow = Worksheets("Sheet1").Range("E" & Rows.Count).End(xlUp).Row
lastRowRpt = tws.Range("A" & Rows.Count).End(xlUp).Row
For i = 3 To lastRow
If Worksheets("Sheet1").Range("E" & i).Value = job And _
Worksheets("Sheet1").Range("D" & i).Value = "x2" Then
Worksheets("Sheet1").Rows(i).Copy
lastRowRpt = tws.Range("A" & Rows.Count).End(xlUp).Row
tws.Range("A" & lastRowRpt + 1).Select
tws.Paste
End If
Next i
End Sub

Excel VBA skips a lot of occurrences

I have a Workbook with 6 Sheets. I am walking through them with For Each. And the task is:
1) Walk though every cell with specified Range
2) If cell is not empty AND contains ONLY number THEN add to the end of the cell " мм". Otherwise SKIP this cell.
But in fact, script does it good only for first sheet (Worksheet). It does no changes to other sheets. I don't know why this happens. I think, that there is some error or mistake in the code, but I double-checked it and everything seems to be correct. Help me please :)
Sub SaveWorksheetsAsCsv()
Dim xWs As Worksheet
Dim xDir As String
Dim folder As FileDialog
Dim r As Range
Dim rr As Range
Dim rrrrrr As Range
Dim cell As Range
k = Cells(Rows.Count, "A").End(xlUp).Row
Set folder = Application.FileDialog(msoFileDialogFolderPicker)
If folder.Show <> -1 Then Exit Sub
xDir = folder.SelectedItems(1)
For Each xWs In Application.ActiveWorkbook.Worksheets
If xWs.Name Like "Worksheet" Then
Set r = Range("FA2:FA" & k)
For Each cell0 In r
If IsEmpty(cell0.Value) = False And IsNumeric(cell0.Value) = True Then
cell0.Value = cell0.Value & " мм"
End If
Next
'xWs.Columns(41).EntireColumn.Delete
End If
If xWs.Name Like "Worksheet 1" Then
Set rr = Range("AG2:AG" & k)
For Each cell1 In rr
If IsEmpty(cell1.Value) = False And IsNumeric(cell1.Value) Then
cell1.Value = cell1.Value & " мм"
End If
Next
'xWs.Columns(126).EntireColumn.Delete
End If
If xWs.Name Like "Worksheet 5" Then
Set rrrrrr = Range("FR2:FR" & k)
For Each cell5 In rrrrrr
If IsEmpty(cell5.Value) = False And IsNumeric(cell5.Value) Then
cell5.Value = cell5.Value & " мм"
End If
Next
End If
xWs.SaveAs xDir & "\" & xWs.Name, xlCSV, local:=True
Next
End Sub
These sets of statements need to be adjusted to correct sheet references. Current code will always look at active sheet and the range reference is not qualified.
Set r = Range("FA2:FA" & k)
Set r = xWs.Range("FA2:FA" & k)
You can shorten-up and utilize your code a lot.
First, your k = Cells(Rows.Count, "A").End(xlUp).Row trying to get the last row, needs to be inside the For Each xWs In Application.ActiveWorkbook.Worksheets , since the last row will be different for each worksheet.
Second, instead of multiple Ifs, you can use Select Case.
Third, there is no need to have 3 different objects for Range, like r, rr, and rrr. The same goes for cell0, cell1 and cell5, you can use just one r and cell.
The only thing different inside your If (my Select Case) is the range you set r. The rest, looping through r.Cells is the same for all 3 criterias, so you can take this part outside the loop, and have it only once.
Modifed Code
Option Explicit
Sub SaveWorksheetsAsCsv()
Dim xWs As Worksheet
Dim xDir As String
Dim folder As FileDialog
Dim r As Range
Dim cell As Range
Dim k As Long
Set folder = Application.FileDialog(msoFileDialogFolderPicker)
If folder.Show <> -1 Then Exit Sub
xDir = folder.SelectedItems(1)
For Each xWs In ThisWorkbook.Worksheets ' it's safer to use ThisWorkbook is you reffer to the worksheets inside the workbook which thid code resides
With xWs
' getting the last row needs to be inside the loop
k = .Cells(.rows.Count, "A").End(xlUp).Row
Set r = Nothing ' reset Range Object
Select Case .Name
Case "Worksheet"
Set r = .Range("FA2:FA" & k)
'xWs.Columns(41).EntireColumn.Delete
Case "Worksheet 1"
Set r = .Range("AG2:AG" & k)
'xWs.Columns(126).EntireColumn.Delete
Case "Worksheet 5"
Set r = .Range("FR2:FR" & k)
End Select
' check if r is not nothing (it passed one of the 3 Cases in the above select case)
If Not r Is Nothing Then
For Each cell In r
If IsEmpty(cell.Value) = False And IsNumeric(cell.Value) Then
cell.Value = cell.Value & " мм"
End If
Next cell
End If
.SaveAs xDir & "\" & .Name, xlCSV, Local:=True
End With
Next xWs
End Sub

For each fails when there is only one cell selected

I am selecting a range into variant in VBA
Dim source as variant
source = Range("A4:A" & rowcount)
and then I am having a for each
For Each element in source
.....
.....
This works when there are 2-3 values selected, but when rowcount is 4,Range("A4:A" & rowcount) will select only a cell and for each is not working
How can I make it work even when only one value is there
I tried
If (rowcount=4) Then
redim preserve source(1)
source(1,1) = source
But it didn't work
You need to make it 2 dimensional
Dim var As Variant
Dim rng As Range
Dim thing As Variant
Set rng = Range("a1")
If rng.CountLarge = 1 Then
ReDim var(1 To 1, 1 To 1)
var(1, 1) = rng.Value2
Else
var = rng.Value2
End If
For Each thing In var
MsgBox thing
Next thing
Try this and check if this works for you:
Where, ThisWorkbook.Sheets(1) refers to Sheet1 of your workbook.
Sub try()
Dim source As Range
RowCount = 4
Set source = ThisWorkbook.Sheets(1).Range("A4:A" & RowCount)
For Each element In source
MsgBox "hi"
Next
End Sub

Complicated multiple select case, variable declarations, range definitions

I developed the code below for a budget template I'm creating from scratch. The purpose is to populate automatically actual GL data information into my assumptions tab in the workbook. I'm using one particular month as a test. I have set up the assumptions tab to have about 26 different sections of regional office information in order to determine an appropriate forecast.
Not all GLs are itemized. I've lumped the GLs for a particular expense (other admin) in categories. I have about 5 major categories of spend and the rest of the GLs are considered as "other". Since the categories are not titled exactly the same as the GL accounts I've had to create a map grid on a separate tab in the workbook to link category names with different GLs.
The end goal is to:
Cycle through each category type on the assumptions tab for each PM region office,
Calculate the total amount for each spend (i.e., Evictions) by PM office plus it's cost center in another workbook,
Calculate the total amount for each spend of Entity code only items from that same other workbook.
The code below only cycle through and calculates the spend for Eviction GLs. I'm looking to improve the code for performance improvement, easier future maintenance(flexibility), and efficiency. The end goal is to cycle through the different types of spend. As of right now, my solution to do that is to repeat the variable/range declarations substituting EvictionRg for the next spend, as well as adding another case.
I'm afraid the code will get too long and performance may be at risk. Any insight and guidance as how I can plan this, modify the code, etc. to help me do this will be greatly appreciated. I've been at this for three days trying to figure it out by actually drawing a process map and other methods to help me brainstorm and by reading other posts on SO. I'm afraid I'm at the end of my VBA knowledge.
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
Whew, that is quite the read! Although I agree with Comintern, I do see a pretty simple solution to trimming up your code, and making it easier to maintain.
I don't see a single function in the entire thing. If you're writing scripts that long, and not using them, you need to start... They'll change your life.
Lets take a simple block that I see repeated several (8) times. Note that I see several much larger blocks that are repeated throughout, but this one will be easy to learn on.
If Not AllEntRg.Find("atlsw", lookat:=xlWhole) Is Nothing Then
Dim as1 As Range
Set as1 = AllEntRg.Find("atlsw", lookat:=xlWhole)
End If
I only see three things that change from if to if in this part of the code, 2 on the input side are a range and a string, and it outputs a range if conditions are met. So you write a function like this, and place it somewhere in any module in the same workbook.
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
Now instead of rewriting this over and over.
If Not AllEntRg.Find("atlsw", lookat:=xlWhole) Is Nothing Then
Dim as1 As Range
Set as1 = AllEntRg.Find("atlsw", lookat:=xlWhole)
End If
You write this over and over.
Dim as1 as Range
set as1 = DefMultiCCPMRange(AllEndRg,"atlsw")
Also the lifetime of the variables that are used in the function, ends when the function ends, so your not storing every variable you use in memory for the entire duration of runtime.
That should take you a long way if you play with it.
I would also look into Arrays, Collections, and Dictionary items. They'll change your life too once you see where their power really lies. You could get creative and instead of declaring and setting that range 8 times, you could do a for loop, and put them all in one object named for the CC Code.
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
This will give you a dictionary object with 4 ranges in it (would be 8 in your actual code), not to mention lose a couple pages of code. You would call the values in the range like odicCCRanges("cahied").Item(1) or odicCCRanges(arrCCCodes(0)).Item(1). Here's where it adds to your project lifetime. If you need to add a new CC, you just change the arrCCCodes declaration to include one more item, then add it below, and the rest of our code will automatically pick it up, run the define ranges function, and add it to the dictionary.
Your code doesn't look all that bad, your testing for nulls, and declaring your vars, all good stuff. It's just all series scripted. Try stepping through your code, and watching the locals window in the VBA IDE. Particularly expand a range node after its set. It'll blow your mind what is actually in a Range Object.
You obviously have a lot of time invested in this but I really think you are over complicating things. Since all your code is doing is building ranges and then summing them I'm thinking you could do this with array formulas.

VBA Type mismatch, Run-time error 13

I just wrote a small VBA function that looks as below. As function output, I would like to get the Range
Public Function selectRows(col As String) As Range
Dim begin, fini As Integer
Set TopCell = Cells(1, col)
Set BottomCell = Cells(Rows.Count, col)
If IsEmpty(TopCell) Then Set TopCell = TopCell.End(xlDown)
If IsEmpty(BottomCell) Then Set BottomCell = BottomCell.End(xlUp)
begin = TopCell.Row
fini = BottomCell.Row
Set selectRows = Activesheet.Range(col & begin & ":" & col & fini)
End Function
Then I get a Type mismatch error when it tries to set output =Range(...)
Could you please help me to fix this issue, thx a lot in advance
It is a very bad idea to use a reserved word such as column as the name of your variable. If you want the function to return a range, you want:
Set selectRows = Range(scol & TopCell.Row & ":" & scol & BottomCell.Row)
Rather than:
Set output = Range(column & TopCell.Row & ":" & column & BottomCell.Row)
There are other problems, such as if the column is empty.
You're putting in an input that is greater than the number of columns that you have. For example, my Excel 2003 has IV columns, when I put in IW it throws the Error 13. I'll leave my code below if you want to clean your code up. Some error handling would help so this wouldn't happen again.
Public Function selectRows(ByVal sColumn As String) As Range
Dim lColumn As Long
Dim TopCell As Range, BottomCell As Range
Dim wks As Worksheet
Set wks = ActiveSheet
lColumn = wks.Range(sColumn & "1").Column
Set TopCell = wks.Cells(1, lColumn)
Set BottomCell = wks.Cells(Rows.Count, lColumn)
If IsEmpty(TopCell) Then Set TopCell = TopCell.End(xlDown)
If IsEmpty(BottomCell) Then Set BottomCell = BottomCell.End(xlUp)
Set selectRows = wks.Range(TopCell, BottomCell)
End Function