Why is a line skipped when running my code? [duplicate] - excel

This question already has an answer here:
Why does Range work, but not Cells?
(1 answer)
Closed 1 year ago.
I'm having issues while running this code. Whenever I do it step by step while pressing F8 it works but whenever I run it skips the Rows(R).EntireRow.Insert line which is the most important. Thank you!
Sub AddARow()
Dim R As Long
Dim FoundCell As Range
Dim revF As Long
Dim nbUnit As Long
Dim moyenneM As Long
Set FoundCell = Sheets("Étude").Range("C1:C200").Find(what:="xxxxx")
R = ((FoundCell.Row) + 2)
Rows(R).EntireRow.Insert
Cells(R, 3).Value = "Moyenne mensuelle par condo"
nbUnit = Cells((R + 4), 4).Value
For i = 4 To 33
revF = Cells((R - 1), i).Value
moyenneM = revF / nbUnit
Cells(R, i).Value = moyenneM / 12
Next
Call AutoFill_TB
End Sub

Its a good practice to explicitly provide the sheet name on which you are performing the action. You can do this by declaring a variable for sheet and a workbook and set that variable. I have modified your code to provide these variables. If you follow this, you will not face the issue, you are currently getting:
Sub AddARow()
Dim R As Long
Dim FoundCell As Range
Dim revF As Long
Dim nbUnit As Long
Dim moyenneM As Long
Dim sh As Worksheet
Dim wkb As Workbook
Set wkb = ThisWorkbook
Set sh = wkb.Worksheets("Étude")
Set FoundCell = sh("Étude").Range("C1:C200").Find(what:="xxxxx")
R = ((FoundCell.Row) + 2)
sh.Rows(R).EntireRow.Insert ' assuming you want to insert in Sheet - Étude
sh.Cells(R, 3).Value = "Moyenne mensuelle par condo"
nbUnit = sh.Cells((R + 4), 4).Value
For i = 4 To 33
revF = sh.Cells((R - 1), i).Value
moyenneM = revF / nbUnit
sh.Cells(R, i).Value = moyenneM / 12
Next
Call AutoFill_TB
End Sub

Related

Need to make excel vba vlookup more efficient

I'm redesigning some finance reports for my organization to move away from a 3rd party software and looking to use VBA to assist in the automation. Haven't written VBA since college, so a little rusty.
I've gotten the code to work, however it's very inefficient and is running at about 1000k records every 30 seconds, which is not feasible with a few hundred thousand records. I've tried several different options that you all have posted in different threads, but must be missing something.
Can you please take a look?
Most threads I've looked at have referenced either a direct input via single cell or same sheet to perform the lookup. This is a single column on Sheet A (ATB-Allowance Reserving-Calc) and then find lookups in table on Sheet B (Plan Global Lookups).
I do want it to skip over errors, and return nothing.
I've tried the fill down method and copy and paste, neither of which I can get to work with a formula. They just seem to want to fill with the value from the original formula.
I'm thinking it's not working due to jumping back and forth between sheets, which I've encountered issues with in different calculations.
I'm not one to just try one or two times, so this is definitely me at the end of my rope.
Dim GlobalExpPct As Variant
Range("AI2").Select 'Gets historical rates from Plan Global Lookups tab
Do
On Error Resume Next
GlobalExpPct = Application.WorksheetFunction.VLookup(ActiveCell.Offset(0, -24), Sheets("Plan Global Lookups").Range("A:B"), 2, False)
ActiveCell.value = GlobalExpPct
GlobalExpPct = vbNullString
ActiveCell.Offset(1, 0).Select
Loop While ActiveCell.Row < 1000 'have this in place to keep it from looping through all the records
I suspect the slow processing is due to selecting of the next cell each time, and then essentially calling the worksheet values and formula again. I'm typically seeing that the formula is returning either null value or getting the same value from the previous formula in the fill down.
Thanks for the help in advance. This is a great resource as I've been able to solve 99% of my issues so far on this site.
Edit
This code provided by Ahmed are working great, but I need one more criteria:
If an additional column ("T" Account Base Class) is "IP", then we can pull from the "Plan Global Lookups A:B" as currently setup. However, if it's populated otherwise, we'll need to pull from a lookup on another column. We can duplicate the table on the same sheet or still use column A as the lookup for the plan, whichever is the most efficient. Here is the code as it stands today which is working perfectly:
Sub GetGlobals()
Dim IntervalProcessing60k As Integer
Dim SRow As Long
Dim ERow As Long
Dim Src As Variant
Dim AcctPlan
Dim GlobalExpPct As Variant
Dim AcctPlanRng As Range
Dim Rslt() As Variant
Dim t As Date
Dim GetGlobalTime As Date
Dim ActWs As Worksheet
Dim ATBAllowResCalc As Worksheet
Set ActWs = ThisWorkbook.ActiveSheet
Set PlanGlobalWs = ThisWorkbook.Sheets("Plan Global Lookups")
Set ATBAllowResCalc = ThisWorkbook.Sheets("ATB-Allowance Reserving-Calc")
Set AcctGlobalRng = PlanGlobalWs.Range("A1:B" & PlanGlobalWs.Cells(PlanGlobalWs.Rows.Count, 1).End(xlUp).Row)
t = Now()
LastRow = Range("A" & Rows.Count).End(xlUp).Row
IntervalProcessing60k = 0
SRow = 2
ERow = LastRow
Src = ActWs.Range("K" & SRow & ":K" & ERow).value
X = 1
For Rw = SRow To ERow
AcctPlan = Src(Rw - SRow + 1, 1)
On Error Resume Next
GlobalExpPct = Application.WorksheetFunction.VLookup(AcctPlan, AcctGlobalRng, 2, False)
On Error GoTo 0
ReDim Preserve Rslt(1 To X)
Rslt(X) = IIf(IsNull(GlobalExpPct), "", GlobalExpPct)
GlobalExpPct = vbNullString
If Rw > 120000 Then Debug.Print Rw, X, Src(Rw - SRow + 1, 1), Rslt(X)
If X = 60000 Then
ActWs.Range("AI" & IntervalProcessing60k * 60000 + SRow).Resize(UBound(Rslt, 1), 1).value = Application.Transpose(Rslt)
IntervalProcessing60k = IntervalProcessing60k + 1
X = 1
ReDim Rslt(1 To 1)
Else
X = X + 1
End If
Next Rw
ActWs.Range("AI" & IntervalProcessing60k * 60000 + SRow).Resize(UBound(Rslt, 1), 1).value = Application.Transpose(Rslt)
GetGlobalTime = Format(Now() - t, "hh:mm:ss")
End Sub
May try this and see if performance improves
Sub testModified()
Dim GlobalExpPct As Variant, Rng As Range, Rw As Long
Dim ValtoLook, Ws As Worksheet, ActWs As Worksheet, tm As Double
tm = Timer
Set ActWs = ThisWorkbook.ActiveSheet
Set Ws = ThisWorkbook.Sheets("Plan Global Lookups")
'Set Rng = Ws.Range("A:B")
'this would be more efficent
Set Rng = Ws.Range("A1:B" & Ws.Cells(Ws.Rows.Count, 1).End(xlUp).Row)
For Rw = 2 To 1000
ValtoLook = ActWs.Range("AI" & Rw).Offset(0, -24).Value
On Error Resume Next
GlobalExpPct = Application.WorksheetFunction.VLookup(ValtoLook, Rng, 2, False)
On Error GoTo 0
Range("AI" & Rw).Value = GlobalExpPct
GlobalExpPct = vbNullString
Next Rw
Debug.Print " Time in second " & Timer - tm; ""
End Sub
if i have not correctly guessed the columns and ranges you are working with, may kindly modify them to your requirement.
It could be made efficient if you confirm there is all the values of Column K and AI are values and they are not inter dependent with some formulas etc. the above code may prove sufficient for 1000 rows. But for heavy files with 10-1000 K rows, the code required to be more efficient. in that case Excel cell operations are to be minimized by using array. Adding above code modified with Array
Sub testModifiedArray()
Dim GlobalExpPct As Variant, Rng As Range, Rw As Long
Dim ValtoLook, Ws As Worksheet, ActWs As Worksheet
Dim Rslt() As Variant, Src As Variant, tm As Double
tm = Timer
Set ActWs = ThisWorkbook.ActiveSheet
Set Ws = ThisWorkbook.Sheets("Plan Global Lookups")
'Set Rng = Ws.Range("A:B")
'next line would be more efficent, You may define range directly if you know the end row
Set Rng = Ws.Range("A1:B" & Ws.Cells(Ws.Rows.Count, 1).End(xlUp).Row)
Src = ActWs.Range("K2:K1000").Value
For Rw = 2 To 1000
ValtoLook = Src(Rw - 1, 1)
On Error Resume Next
GlobalExpPct = Application.WorksheetFunction.VLookup(ValtoLook, Rng, 2, False)
On Error GoTo 0
ReDim Preserve Rslt(1 To Rw - 1)
Rslt(Rw - 1) = IIf(IsNull(GlobalExpPct), "", GlobalExpPct)
'Debug.Print Rslt(Rw - 1)
GlobalExpPct = vbNullString
Next Rw
ActWs.Range("AI2").Resize(UBound(Rslt, 1), 1).Value = Application.Transpose(Rslt)
Debug.Print " Time in second " & Timer - tm; ""
End Sub
Both the code tested with my Guess of Column and ranges. As I personally don't prefer to keep calculations, event processing and screen updating off (in normal cases) i haven't added that standard lines. However you may use these standard techniques, depending on the working file condition.
Edit: modified to accommodate overcome 65K limit of array transpose limt
Option Explicit
Sub testModifiedArray2()
Dim GlobalExpPct As Variant, rng As Range, Rw As Long
Dim ValtoLook, Ws As Worksheet, ActWs As Worksheet
Dim Rslt() As Variant, Src As Variant, tm As Double
Dim Chunk60K As Integer, X As Long, SRow As Long, ERow As Long
tm = Timer
Set ActWs = ThisWorkbook.ActiveSheet
Set Ws = ThisWorkbook.Sheets("Plan Global Lookups")
'Set Rng = Ws.Range("A:B")
'next line would be more efficent, You may define range directly if you know the end row
Set rng = Ws.Range("A1:B" & Ws.Cells(Ws.Rows.Count, 1).End(xlUp).Row)
Chunk60K = 0
SRow = 2
ERow = 120030
Src = ActWs.Range("K" & SRow & ":K" & ERow).Value
X = 1
For Rw = SRow To ERow
ValtoLook = Src(Rw - SRow + 1, 1)
On Error Resume Next
GlobalExpPct = Application.WorksheetFunction.VLookup(ValtoLook, rng, 2, False)
On Error GoTo 0
ReDim Preserve Rslt(1 To X)
Rslt(X) = IIf(IsNull(GlobalExpPct), "", GlobalExpPct)
GlobalExpPct = vbNullString
If Rw > 120000 Then Debug.Print Rw, X, Src(Rw - SRow + 1, 1), Rslt(X)
If X = 60000 Then
ActWs.Range("AI" & Chunk60K * 60000 + SRow).Resize(UBound(Rslt, 1), 1).Value = Application.Transpose(Rslt)
Chunk60K = Chunk60K + 1
X = 1
ReDim Rslt(1 To 1)
Else
X = X + 1
End If
Next Rw
ActWs.Range("AI" & Chunk60K * 60000 + SRow).Resize(UBound(Rslt, 1), 1).Value = Application.Transpose(Rslt)
Debug.Print " Time in second " & Timer - tm; ""
End Sub
Last Answer modified for improved efficiency and new requirement, Test time to process around 120 K rows is around 6 seconds only. additionally column "T" is tested for a value "IP" and lookup value pulled up from column B or C accordingly.
Option Explicit
Sub GetGlobals()
Dim SRow As Long
Dim ERow As Long
Dim Src As Variant, Src2 As Variant
Dim AcctPlan
Dim GlobalExpPct As Variant
Dim AcctPlanRng As Range
Dim Rslt() As Variant
Dim tm As Double
Dim ActWs As Worksheet, PlanGlobalWs As Worksheet
Dim AcctGlobalRng As Range
Dim ATBAllowResCalc As Worksheet
Dim LastRow As Long, X As Long, Rw As Long
Dim LookArr As Variant, LookUpCol As Integer
Set ActWs = ThisWorkbook.ActiveSheet
Set PlanGlobalWs = ThisWorkbook.Sheets("Plan Global Lookups")
'Set ATBAllowResCalc = ThisWorkbook.Sheets("ATB-Allowance Reserving-Calc")
Set AcctGlobalRng = PlanGlobalWs.Range("A1:C" & PlanGlobalWs.Cells(PlanGlobalWs.Rows.Count, 1).End(xlUp).Row)
LookArr = AcctGlobalRng.Value
tm = Timer
LastRow = Range("K" & Rows.Count).End(xlUp).Row
SRow = 2
ERow = LastRow
Src = ActWs.Range("K" & SRow & ":K" & ERow).Value
Src2 = ActWs.Range("T" & SRow & ":T" & ERow).Value
ReDim Rslt(1 To ERow - SRow + 1, 1 To 1)
For Rw = SRow To ERow
AcctPlan = Src(Rw - SRow + 1, 1)
GlobalExpPct = ""
For X = 1 To UBound(LookArr, 1)
If AcctPlan = LookArr(X, 1) Then
LookUpCol = IIf(Src2(Rw - SRow + 1, 1) = "IP", 2, 3)
GlobalExpPct = LookArr(X, LookUpCol)
Exit For
End If
Next X
GlobalExpPct = IIf(IsNull(GlobalExpPct), "", GlobalExpPct)
Rslt(Rw - SRow + 1, 1) = GlobalExpPct
Next Rw
ActWs.Range("AI" & SRow).Resize(UBound(Rslt, 1), 1).Value = Rslt
Debug.Print " Time in second " & Timer - tm; ""
End Sub

application.match returns a value where one does not exist

I am not great at this yet, but I am trying to do this without copy-pasting code... not sure its the best idea.
I am trying to search for to different values in two columns and then return a different if both columns match. In the end I will be pulling from about 9 different workbooks.
Dim wbACF As Workbook
Dim wsDiv As Worksheet
Dim rng As Range
Dim WC As String
Dim vCELL As Variant
Dim switch As Variant
Dim nvCell As Variant
Dim lastCell As Variant
Set wbACF = Workbooks("ACF.xls")
WC = Sheet1.Cells(5, 14).Value
nvCell = "A1"
lastCell = "A999"
Set wsDiv = wbACF.Worksheets(WC)
Set rng = wsDiv.Range(nvCell, lastCell)
switch = 1
Do While switch = 1
vCELL = Application.Match("test", rng, 0)
If wsDiv.Cells(vCELL, 7).Value = Sheet1.Cells(5, 13).Value Then
Sheet1.Cells(11, 1).Value = wsDiv.Cells(vCELL, 4)
switch = 0
Else
nvCell = "A" & vCELL + 1
Set rng = wsDiv.Range(nvCell, lastCell)
End If
Loop
for my test files, rows 10, 70, 150 and 210 match for test, but only row 210 match for both test and Sheet1.Cells(5, 13).Value
vCELL becomes 10 in the first loop, and then executes the else portion, on the second loop vCELL becomes 60 and then never changes. I am sure my coding is poor, and is a contributing factor, but any help would be appriciated.

VBA for loop only iterating once

I'm having trouble with this VBA - my for loop only iterates once, and when it increments it says that the method "Cells" in object "Worksheet" failed. It worked the first iteration though... I think my StatusUpdate function is breaking it, but when I comment it out, it fails anyway. Does anything stand out in the main sub to anyone? Happy to post more code if needed.
Sub CreateSlides()
Dim XLapp As New Excel.Workbook
Dim WS As New Excel.Worksheet
Set XLapp = Excel.Workbooks.Open("J:\OPERATIONS\CAPITAL PROJECTS\Clara\test.xlsx")
Set WS = XLapp.Sheets(1)
XLapp.Activate
WS.Select
Dim CD As Integer
CD = 0
Dim cell As Range
Dim i As Integer
Dim LastRow As Integer
LastRow = WS.Cells(WS.Rows.Count, 1).End(xlUp).Row
'Delete old slides
If ActivePresentation.Slides.Count > 1 Then
Call DeleteSlides
End If
'Loop through each used row in Column A
For i = 2 To LastRow
CD = WS.Cells(i, 35).Value
ActivePresentation.Slides(1).Copy
ActivePresentation.Slides.Paste (ActivePresentation.Slides.Count + 1)
ActivePresentation.Slides(ActivePresentation.Slides.Count).Shapes("project").TextFrame.TextRange = WS.Cells(i, 7).Value
ActivePresentation.Slides(ActivePresentation.Slides.Count).Shapes("park location").TextFrame.TextRange = WS.Cells(i, 9).Value
ActivePresentation.Slides(ActivePresentation.Slides.Count).Shapes("cb").TextFrame.TextRange = Right(WS.Cells(i, 36).Text, 2)
ActivePresentation.Slides(ActivePresentation.Slides.Count).Shapes("cm").TextFrame.TextRange = (CouncilMember(CD))
ActivePresentation.Slides(ActivePresentation.Slides.Count).Shapes("scope").TextFrame.TextRange = WS.Cells(i, 8).Value
ActivePresentation.Slides(ActivePresentation.Slides.Count).Shapes("funding").TextFrame.TextRange = FundingEst(i)
ActivePresentation.Slides(ActivePresentation.Slides.Count).Shapes("status").TextFrame.TextRange = StatusUpdate(i)
Next
End Sub
you a re not running through column a but to the 35th column in the sheet. change
CD = WS.Cells(i, 35).Value
to
CD = WS.Cells(i, 1).Value
Also, if whatever is in those cells is not an integer, but text or something else, you will get an error?

Exceeding row limit - create new sheet

I have 2 columns on a sheet "list", one column that lists all business entities, the other lists all org units. The functionality of the code below works perfectly but returns an error because it exceeds the sheet row limit.
The data is pasted onto a sheet "cc_act" is there a way to at point of error create a new sheet called "cc_act1"...."cc_act2" until the script is complete?
Declare Function HypMenuVRefresh Lib "HsAddin" () As Long
Sub cc()
Application.ScreenUpdating = False
Dim list As Worksheet: Set list = ThisWorkbook.Worksheets("list")
Dim p As Worksheet: Set p = ThisWorkbook.Worksheets("p")
Dim calc As Worksheet: Set calc = ThisWorkbook.Worksheets("calc")
Dim cc As Worksheet: Set cc = ThisWorkbook.Worksheets("cc_act")
Dim cc_lr As Long
Dim calc_lr As Long: calc_lr = calc.Cells(Rows.Count, "A").End(xlUp).Row
Dim calc_lc As Long: calc_lc = calc.Cells(1,
calc.Columns.Count).End(xlToLeft).Column
Dim calc_rg As Range
Dim ctry_rg As Range
Dim i As Integer
Dim x As Integer
list.Activate
For x = 2 To Range("B" & Rows.Count).End(xlUp).Row
If list.Range("B" & x).Value <> "" Then
p.Cells(17, 3) = list.Range("B" & x).Value
End If
For i = 2 To Range("A" & Rows.Count).End(xlUp).Row
If list.Range("A" & i).Value <> "" Then
p.Cells(17, 4) = list.Range("A" & i).Value
p.Calculate
End If
p.Activate
Call HypMenuVRefresh
p.Calculate
'''changes country on calc table
calc.Cells(2, 2) = p.Cells(17, 4)
calc.Cells(2, 3) = p.Cells(17, 3)
calc.Calculate
'''copy the calc range and past under last column
With calc
Set calc_rg = calc.Range("A2:F2" & calc_lr)
End With
With cc
cc_lr = cc.Cells(Rows.Count, "A").End(xlUp).Row + 1
calc_rg.Copy
cc.Cells(cc_lr, "A").PasteSpecial xlPasteValues
End With
Next i
Next x
Application.ScreenUpdating = True
End Sub
I suppose there are a few ways to handle something like this. See the code sample below, and adapt it to your specific needs.
Sub LongColumnToAFewColumns()
Dim wsF As Worksheet, WST As Worksheet
Dim rf As Range, rT As Range
Dim R As Long, j As Integer
' initialize
Set wsF = ActiveSheet
Set WST = Sheets.Add
WST.Name = "Results"
j = 1
For R = 1 To wsF.Cells(Rows.Count, 1).End(xlUp).Row Step 65536
wsF.Cells(R, 1).Resize(65536).Copy
WST.Cells(j, 1).PasteSpecial xlPasteValues
WST.Cells(j, 1).PasteSpecial xlPasteValues
j = j + 1
Next R
End Sub
As an aside, you may want to consider using MS Access for this kind of thing. Or, better yet, Python or even R. Good luck with your project.

Error 1004 Vlookup VBA

I have yet again another question to ask regarding VBA. I'm currently trying to use the VLookUp function. Here is all the information relevant to the code:
Dim Template_Sheet As Worksheet
Dim Database_Sheet As Worksheet
Dim Source_Sheet As Worksheet
Dim FileUpdate As Worksheet
Set Template_Sheet = Sheets("Template")
Set Database_Sheet = Sheets("Database")
Set Source_Sheet = Sheets("Source")
Set FileUpdate = Sheets("NewFile")
Dim Database_Row_Count As Integer
Dim Database_Column_Count As Integer
Dim id_temp As String
Dim Row_Count As Integer
Dim Lat_Index As Integer
For i = 1 To FileUpdate.Rows.Count 'Count Rows
If IsEmpty(FileUpdate.Cells(i, 1)) Then
Row_Count = i - 1
Exit For
End If
Next i
Lat_Index = Source_Sheet.Cells(6, 1).Value
Database_Row_Count = Source_Sheet.Cells(6, 4).Value
Database_Column_Count = Source_Sheet.Cells(6, 5).Value
For i = 2 To (1 + Row_Count)
id_temp = Template_Sheet.Cells(i, 1).Value
Template_Sheet.Cells(i, 2).Value = Application.WorksheetFunction.VLookup(id_temp, Database_Sheet.Range(Database_Sheet.Cells(2, 1), Database_Sheet.Cells(Database_Row_Count, Database_Column_Count)), Lat_Index, False)
Next i
I get, you guessed it, Error 1004 on run. I've used almost all of these values for other applications within the sub, so I suspect my error must be coming from a miss-defined parameter when calling the VLookup function. Help is much appreciated.
Thanks!
D.

Resources