How to get speed up data getting by ignoring empty cells? - excel

I've ran into a problem with a processing tool I'm working on, namely with the initial hang time being close to 10 seconds long. The issue I'd identified is that when the data is originally Imported into the it proceeds to update every lookup array and function in the 5x1000 workspace. I've been thinking that a good way to speed up the processing was to limit the import to non-empty cells only but have been unable to get it done no matter what I tried.
By default this is the function that imports the data from the RadGridExport temp file into a buffer sheet for later processing:
Sub CopyData()
Dim rng As Range
Set rng = Workbooks("RadGridExport.xls").Sheets(1).Range("A1:E1000")
ThisWorkbook.Sheets(2).Range("A1").Resize(rng.Rows.Count, rng.Columns.Count).Cells.Value = rng.Cells.Value
End Sub
I have attempted to use IsEmpty(Cell.Value) method but that was less than effective
Sub CopyData()
Dim rng As Range
Set rng = Workbooks("RadGridExport.xls").Sheets(1).Range("A1:E1000")
For Each Cell In rng
If IsEmpty(Cell.Value) = False Then
ThisWorkbook.Sheets(2).Range("A1").Resize(rng.Rows.Count, rng.Columns.Count).Cells.Value = rng.Cells.Value
End If
Next Cell
End Sub
In fact it froze the entire workbook. That was the only way I'm familiar with that could have applied, so I'm in a bit of a dead end.
Is there a way to actually get my initial function to ignore empty cells? Or am I coming at this from the wrong way and there's some method for keeping the worksheet from doing a full update on every single cell, including those whose value doesn't change?

I have managed to find a solution to my problem.
First of all thank to #Pᴇʜ for an way to do dynamic ranges - I ended up not using it in this tool as a lot of processing relies on static cells in a range for auto calculations, but I have written it down for the future!
#JvdV 's suggestion worked like a charm, bringing the load time down from 31 seconds to 14 seconds average.
Current codes looks like this:
Sub CopyData()
Dim rng As Range
Set rng = Workbooks("RadGridExport.xls").Sheets(1).Range("A1:E1000").SpecialCells(2)
ThisWorkbook.Sheets(2).Range("A1").Resize(rng.Rows.Count, rng.Columns.Count).Cells.Value = rng.Cells.Value
End Sub
However it was still forcing a full refresh on all static values - so after digging deeper I realized that I was using a massively taxing clear gate in the main macro:
Sub clearAll()
Range("A:E").ClearContents
End Sub
Which caused that massive 14 second delay. After I changed that function to this:
Dim Workspace As Range
Set Workspace = ThisWorkbook.Sheets(2).Range("A1:E1000")
For Each Cell In Workspace
If IsEmpty(Cell.Value) = False Then
Cell.ClearContents
End If
Next Cell
The load time went down further from 14 seconds to under 2 seconds total.
Thanks again :)

Related

Advice about excel vba scripts

i need advice about vba scripting, macros.
So, i have excel table with 3 sheets named: Predujam, OSTATAK NAKNADE, vlookup
Predujam and OSTATAK NAKNADE contains vlookup/xlookup formula which are pulling data from vlookup sheet.
All 3 sheets contain like 4000 lines of data, columns range is A:Q.
For sheet Predujam i use this code (this code is supposed to do calculation only in the rows where the changes occurred):
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
Set KeyCells = ThisWorkbook.Sheets("PREDUJAM").Range("A2:O5000")
If Not Application.Intersect(KeyCells, Range(Target.Address)) _
Is Nothing Then
Range("A" & Range(Target.Address).Row & ": O" & Range(Target.Address).Row).Calculate
End If
End Sub
For sheet OSTATAK NAKNADE use same code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
Set KeyCells = ThisWorkbook.Sheets("OSTATAK NAKNADE").Range("A2:O5000")
If Not Application.Intersect(KeyCells, Range(Target.Address)) _
Is Nothing Then
Range("A" & Range(Target.Address).Row & ": O" & Range(Target.Address).Row).Calculate
End If
End Sub
In sheet vlookup
I am using only this code to calculate that sheet only when it is opened:
Private Sub Worksheet_Activate()
Worksheets("vlookup").Calculate
End Sub
And in ThisWorkbook i inserted code that stops automatically calculation:
Private Sub Workbook_Open()
Application.Calculation = xlManual
Application.CalculateBeforeSave = False
End Sub
So basically i wanted to stop all calculations and to calculation only in the rows where the changes occurred.
Problem is: table is still laggy, saving still takes like 20-30 sec to save, and calculation in rows where the changes occurred is also doing with some delay.
My Question: Do i have some mistakes in the codes which could cause lagginess? If there is any better way to write this, can you please tell me how to rewrite it?
I am just beginner in vba scripting so i need some advices.
Thanks! :D
This isn't a proper answer, but a comment doesn't afford me enough space to write all of this...
As someone using VBA you probably appreciate the value of variables, i.e.
calculate something once,
'remember' it in a variable, and then
you can reference that variable efficiently multiple times, rather than, inefficiently, recalculating the something afresh every time you need to use it
Helper cells in the user-interface, while much maligned, are the equivalent of variables in this regard, i.e.
something is calculated once,
'remembered' in a designated cell, and then
that cell can be referenced whenever the result is required, rather than having every formula that needs the result recalculate it from first principles.
Why am I rambling about this ? Given that you are setting Workbook calculation to manual, your file is obviously spending a lot of time calculating: if you audit the formulae in the workbook then you will likely find at least some calculations common to several formulae - if you extract these calculations to designated helper cells, then you can improve performance by having those results calculated only once, and then just referenced from the 'old formulae' rather than having the calculations repeated in each formula in which they currently occur.

best way to select column based on current date (Excel VBA)

I have a small tracker program I am building in Excel VBA. I have a userform that I keep up throughout the day, inputting my tasks/data via an 'Add' button. At the end of the day, I click the 'Post' button, and it saves the data to my worksheets where appropriate.
Thought I had it finished and working correctly, but now apparently my sub to select the correct column based on the day's date is not working, and I'm not sure why, as it had been working perfectly throughout development.
This piece is vital, as my other functions to post the day's data rely on this. I've read a lot of other posts about how to do this (selecting a column based on current date), but none have explained why mine isn't working. Trying to become a better coder, and not just a copy/paste coder, so thought I would try asking here. Copy/Paste usually gets me into these messes, where I'm using tools/functions that work, but I don't know why, and can't troubleshoot/debug on my own.
My total project involves 5 worksheets, but this sub should only involve 2 of them. "Tasks" and "Data Tracker", both of which have a row of dates.
Below is the sub in question.
Public Sub currentDate()
'sub to assign current date to global values
Set rng - Range("H2:HZ2")
Set myDate = rng.Find(What:=Int(Date), LookIn:=xlFormulas)
End Sub
If I step through it, Date is pulling the correct date, and xlFormulas shows a value of -4123 (I don't even know if that matters)..
(UPDATE) so apparently, this morning, it decided to work perfectly. facepalm Any clues?
(UPDATE) so, per usual, I try adding features as I fix something else, so this took a bit more researching to solve, but #Super-Symmetry pointed me in the right direction! As noted in a comment down below, I changed my date headers in the two sheets to be more of a "start date + n" situation. Although his suggestion of using xlValue instead of xlFormula was on the right track, Find. was still having trouble with date vs serial. Ultimately this is what I got to work:
Public Sub currentDate()
'sub to assign current date to global values
'load the date range
Set rng = Worksheets("Tasks").Range("H2:HZ2")
'load the values in the range
dateArray = Range("H2:HZ2").Value
Dim day As Variant 'object to load dateArray
Dim loc As Integer 'matches date with cell location
'converting the date to serial
For Each day In dateArray
day = CLng(day)
loc = loc + 1
If day = Date Then 'we found the right column
Set myDate = rng(loc)
'selects the correct cell
If ActiveSheet.name = "Data Tracker" Then 'adjust the row
Cells(myDate.Row + 3, myDate.Column).Select
Else 'sheet must be Tasks
Cells(myDate.Row + 2, myDate.Column).Select
End If
Exit Sub
End If
Next
End Sub
It's not elegant, but it works.. please feel free to educate me if you have any cleaner ways to do this!
Try changing Int(Date) to CLng(Date)
Public Sub currentDate()
'sub to assign current date to global values
Dim rng As Range, myDate As Range
Set rng = Range("H2:HZ2")
Set myDate = rng.Find(What:=CLng(Date), LookIn:=xlValues)
End Sub

Application Defined or oBject Defined Error - Cannot Solve

Sub gains()
Dim date_data As Long
Dim date_h As Long
Dim cell As Range
Dim analysis_rng As Range
Dim data_h As Range
Set analysis_rng = Application.Worksheets("DataDPI").Range("A2:A107")
Set data_h = Application.Worksheets("Data").Range("A2:A525")
For Each cell In analysis_rng
cell.Offset(0, 2) = data_h.Find(cell, LookIn:=xlValues)
Next cell
End Sub
It was working and then stopped working. Data is the same and the worksheets are labeled correctly. Error 1004
Spent 15 minutes trying to debug already
I can fill the cell.offset(0,4) with text/number just fine but I can no longer do data_h.find (range.find). i was testing it earlier and was working okay```
Purpose
I have a main dataset, it's a bunch of dates open close prices: workhseet "Data"
Secondary set is a select few dates from the main data set and other . I am just trying to see what changes are but before that, I just want to make sure i'm referencing the right data
So in the code posted above, once it was copying over the right data from "data" to cell.offset, I was going to just use offset to collect data as I wanted from main set: data_h to the new "DataDPI"

Using a variable for a range

I am writing a macro and am having issues with using a range variable. I think I am setting the range properly, but I cannot do anything with the range. Pseudocode below:
Dim rng As Range
Set rng = Report(1) 'A function which will be defined below
trackWkbk.Sheets(strFY).rng = 10 <--'THIS IS WHERE I am getting the error.
'trackWbkb is a workbook that is defined properly; I use it elsewhere with no errors.
'strFY is defined and working properly, I use it to call sheets in trackWbkb elsewhere with no errors.
The sub function code is:
Function Report(a) As Range
Select Case intMonth
Case intMonth = 7
Select Case a
Case a = 1
Set Report = Range("B2")
End Select
End Select
End Function
I know my select case statements are gonna get pretty convoluted (this is just a testing sample), but I don't think the issue is there.
Let me know if I should include more code. My code compiles. I think this is something simple that I am missing, but I have been looking online for the past half hour and can't seem to find anything that will resolve this. Does anyone know how to resolve this? Thanks
Your function already returns a Range object. It's not clear to me whether you're trying to obtain a range on another worksheet that is at the same address as a range on the active worksheet. However, you could directly obtain the desired range if you passed the worksheet reference to your function:
Function Report(ByVal poParentWorksheet As Excel.Worksheet, ByVal a As Integer) As Range
Select Case intMonth
Case intMonth = 7
Select Case a
Case a = 1
Set Report = poParentWorksheet.Range("B2")
End Select
End Select
End Function
Then you could use:
Set rng = Report(trackWkbk.Sheets(strFY), 1)
rng.Value = 10
When you set a range variable you are creating a pointer in memory to a specific range in a specific sheet. It's not storing a cell address, so you can't write
trackWkbk.Sheets(strFY).rng
Either adopt Excelosaurus's solution, or change your function to return a cell address as a string and then use
trackWkbk.Sheets(strFY).range(rng)

#VALUE error when copying sheets

I´m using a UDF that is basically a vlookup simplified. Here´s the code:
Function SUELDOBASICO(Columna As Integer) As Double
SUELDOBASICO = Application.WorksheetFunction.VLookup(Application.Caller.Parent.Cells(Application.Caller.Row, 3), Application.Caller.Parent.Parent.Sheets("Escalas Salariales").Range("A3:DJ23"), Columna, False)
End Function
I´ve noticed that sometimes when copying sheets(within the same workbook), I get a #VALUE error. If I "edit" the cell in Excel, changing nothing, just using F2 and Enter, the error disappears. It used to happen when simply changing windows (to Firefox, and back to Excel, for instance). That´s why I used Caller and Parent so much in the code. It is almost completely fixed, except when copying sheets sometimes. I can´t seem to find the source of the error.
Help please.
I know this isn't your exact question, but, if at all possible, I would suggest to just avoid VBA completely if that's at all an option and write your formula as follows:
=VLOOKUP(INDIRECT("C"&ROW()),'Escalas Salariales'!$A$3:$DJ$23,XXXXX,false)
and XXXXX can be the same as your Columna variable currently.
That would guarantee your code to work as needed.
Given what was discussed in the comments and trying my absolute best to ensure this works, I actually don't see anything wrong with your code and am just GUESSING it may have something to do with Application.Caller.
When this kind of thing happens to me, I try my best to just use the debugger to figure out why - That usually involves either Stop statements to be able to step into code and see what happened or Debug.Print Err.Description kind of messages.
Either way, I tried to break each part down, so, at the very least you can see where the issue comes from.
To do so, I re-worked your function (with some major overkill)....
Function SUELDOBASICO(Columna As Integer) As Double
On Error GoTo ErrorCheck
Dim CellRef As Range
Dim LookupRef As Range
Set CellRef = Cells(Application.Caller.Range("A1").Row, 3)
Set LookupRef = Application.Caller.Worksheet.Parent.Sheets("Escalas Salariales").Range("A3:DJ23")
SUELDOBASICO = Application.VLookup(CellRef, LookupRef, Columna, False)
Exit Function
ErrorCheck:
Stop
Resume
End Function
(Also note that I changed Application.WorksheetFunction.VLookup to Application.VLookup - Look at this link for an explanation)
Once you figure it out, I would, though, remove the error code from the function as that isn't a good idea for production code - Just for Debugging.
Hopefully that can give you the answers you are looking for.
Hope that helps....
UPDATE #2:
Taking into account the possibility that copying the sheet is causing this error, here's a test to see if the process gets fixed:
Function SUELDOBASICO(Columna As Integer) As Double
On Error GoTo ErrorCheck
Dim NumTimesErrored As Integer
Dim StartTime As Double
Dim WaitSeconds As Integer
NumTimesErrored = 0
Dim CellRef As Range
Dim LookupRef As Range
Set CellRef = Cells(Application.Caller.Range("A1").Row, 3)
Set LookupRef = Application.Caller.Worksheet.Parent.Sheets("Escalas Salariales").Range("A3:DJ23")
SUELDOBASICO = Application.VLookup(CellRef, LookupRef, Columna, False)
Exit Function
ErrorCheck:
' This will make it tries this "hack" up to 3 times:
If NumTimesErrored < 3 Then
StartTime = Now
WaitSeconds = 1 ' Wait one second
Loop While Now - TimeStart < TimeSerial(0, 0, WaitSeconds)
DoEvents ' Allows all the other processes to complete
Loop
' Increment the number of times you've tried this:
NumTimesErrored = NumTimesErrored + 1
' Go back to the calculation step that errored
Resume
End If
Stop
Resume
End Function
The is no need to use caller and parent.
Function SUELDOBASICO(Cell as Range, LookupRange as range, Columna As Integer) As Double
' When you call the function :
' set Cell to be the cell in column C in the same row
' Set LookupRange to Sheets("Escalas Salariales").Range("$A$3:$DJ$23")
SUELDOBASICO = Application.WorksheetFunction.VLookup(Cell, LookupRange, Columna, False)
End Function
example of formula in a cell...
=SUELDOBASICO(C10,'Escalas Salariales'!$A$3:$DJ$23)

Resources