Speeding up VBA Code to Run Faster - vba

I have an Excel Workbook where the user imports a text file by the click of a button. My code works exactly as I need it to but it is extremely slow when filling in column H, Reading Date. Here is what my Excel Workbook looks like when the text file has been imported to the excel sheet:
Here is my code:
Sub Import_Textfiles()
Dim fName As String, LastRow As Integer
Worksheets("Data Importation Sheet").Activate
LastRow = Range("A" & Rows.Count).End(xlUp).Row + 1
' Finds the first blank row to import text file data to
fName = Application.GetOpenFilename("Text Files (*.txt), *.txt")
If fName = "False" Then Exit Sub
With ActiveSheet.QueryTables.Add(Connection:="TEXT;" & fName, _
Destination:=Range("A" & LastRow))
.Name = "2001-02-27 14-48-00"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = False
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 437
.TextFileStartRow = 2
.TextFileParseType = xlFixedWidth
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = True
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1)
.TextFileFixedColumnWidths = Array(14, 14, 8, 16, 12, 14)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
ActiveWindow.SmallScroll Down:=0
Dim strShortName As String
'Adding Reading Date to Excel Sheet:
Dim rowCount As Integer, currentRow As Integer
Dim sourceCol As Integer, nextCol As Integer
Dim currentRowValue As String
Dim fileDate1 As String
Dim fileDate2 As String
sourceCol = 1 'columnA
nextCol = 8 'column H
rowCount = Cells(Rows.Count, sourceCol).End(xlUp).Row
strShortName = fName
fileDate1 = Mid(fName, InStrRev(fName, "\") + 1)
fileDate2 = Left(fileDate1, 10)
Cells(LastRow, 9) = ("Updating Location: " & strShortName)
For currentRow = 1 To rowCount
currentRowValue = Cells(currentRow, nextCol).Value
If currentRowValue = "" Then
Cells((currentRow), (nextCol)).Select
Cells((currentRow), (nextCol)) = fileDate2
End If
Next
End Sub
If anyone has any suggestions as to how I can speed up the importation of the reading date I would appreciate it greatly! Thanks in advance!

Few things that I noticed
As mentioned by Chris in comments, you can turn off screen updating and set calculation to manual and switch them back on and set calculation to automatic at the end of the code.
For Example
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
'
'~~> Rest of your code
'
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
Avoid the use of .Select. it reduces the speed of the code. You do not need to select the cell to write to it.
Your For Loop can be written as.
For currentRow = 1 To RowCount
If Cells(currentRow, nextCol).Value = "" Then
Cells(currentRow, nextCol).Value = fileDate2
End If
Next
This it self will increase the speed of your code as you are not selecting the cell anymore before writing to it.
Ideally I would copy the range to an array and then do what you are doing with the array and then write it back to the cell but then that is me.
Remove unnecessary lines of code. ActiveWindow.SmallScroll Down:=0 is not needed.
Work with object(s) and fully qualify your object(s).
When working with Excel rows, use Long instead of Integer

Try this:
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
YOUR CODE HERE
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.EnableEvents = True

The best solution depends on a few things, that aren't clear to me from provided data. The following change will speed it up a lot (selecting cells takes a lot of time), but its not the optimum. If its still to slow, please provide ~ number of rows and ~% of rows (in column H), that are filled before you get to the following code. Then either searching for missing values or (probably in most cases) copying column H into an array and copying back after updating the values will do the trick.
Old code:
For currentRow = 1 To rowCount
currentRowValue = Cells(currentRow, nextCol).Value
If currentRowValue = "" Then
Cells((currentRow), (nextCol)).Select
Cells((currentRow), (nextCol)) = fileDate2
End If
Next
New code:
For currentRow = 1 To rowCount
if Cells(currentRow, nextCol).Value = "" then
Cells(currentRow,nextCol).Value = fileDate2
End If
Next

Related

Range Class Selection Syntax Error Between Multiple Sheets

I have been designing a macro that imports text files into Excel. The program was designed to initially import all data into sheet 1, but after getting feedback I was told to have it bring all data into sheet 2 instead. This macro had no trouble working when using commands such as Activesheet at the beginning of code lines, because sheet1 was always the active sheet. *Note both all sheets have their default names.
I have gone in and tried to change all my range fns to regard sheet 2 instead by typing Worksheets("Sheet2").Range("A1")... ,but this has given me the
"Select method of Range class"
error. This error occurs after my initial fn to import the file using a Query table.
Option Explicit
Sub importtxt()
Dim txtloc As Variant
Dim build As String
Dim bit As String
Dim rng As Range
'Asks user for the build number that has been imported, then assigns that
string to cell B1
build = InputBox("What build of SoundCheck is this?")
'Prompt Bitness
bit = InputBox("Please provide the bitness of this SoundCheck")
'Asks user for location of the Time_Memlog.txt file to be imported
txtloc = Application.GetOpenFilename _
(FileFilter:="Text Filer (*.txt),*.txt", _
title:="Open File(s)", MultiSelect:=False)
'Imports .txt file designated in the txtloc string
With Sheets("Sheet2").QueryTables.Add(Connection:="TEXT;" & txtloc,
destination:=Worksheets(2).Range("$A$1"))
.Name = "Sample"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 437
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = True
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = True
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
'Clears the garbage in cell A1
Worksheets("Sheet2").Range("$A$1").Select
ActiveCell.Clear
'Places the string build in cell A1
Worksheets(2).Range("A1").Select
ActiveCell.Value = "Build:"
Worksheets(2).Range("B1").Select
ActiveCell.Value = build
Worksheets(2).Range("C1").Select
ActiveCell.Value = bit
'Selects all columns of the Time_Memlog and adjusts the column width to fit
heading
Worksheets(2).Range("A1:S10003").Select
Selection.Columns.AutoFit
'Makes column headers bold text
Sheets("Sheet2").Range("A2:D2").Font.Bold = True
'Create borders around cell range A2:D2
Set rng = Worksheets(2).Range("A2:D2")
With rng.Borders
.LineStyle = xlContinuous
.Weight = xlThin
End With
'Give background color to cells A2:D2
With rng.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorAccent6
.TintAndShade = 0.599993896298105
.PatternTintAndShade = 0
End With
'Aligns all cells below Column headers to the left
Worksheets(2).Range("A3:D10003").Select
Selection.HorizontalAlignment = xlLeft
'Give background color to cells A1:C1
Worksheets(2).Range("A1:C1").Select
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorDark1
.TintAndShade = -0.149998474074526
.PatternTintAndShade = 0
End With
Selection.HorizontalAlignment = xlLeft
Worksheets(2).Range("D1").Select
Selection.Clear
End Sub
This seems like a very simple problem, yet I don't know how to get around these errors.
Two answers:
The bad news: You cannot select a cell or range from a worksheet that is not active.
The good news: No need to select a cell to assign a value (or do anything else with it). In fact you should avoid to select anything within VBA, there is nearly no reason to do so. Instead, simply do something like
with Worksheets(2)
.range("A2").value = "Build:"
' or: .cells(1,1).value = "Build:"
...
end with

How to lock in an "ActiveCell.Vale" variable in VBA after changing the active cell?

enter image description hereI'm trying to compare two variables within a macro but those two variables are going to be changing. Here's what I have so far:
Selection.End(xlToRight).Select
Dim Year As Integer
Year = ActiveCell.Value
ActiveCell.Offset(-1, 0).Select
Dim Year2 As Integer
Year 2 = ActiveCell.Value
If Year2 <> Year + 1 Then
ActiveCell.Offset(1, 0).Select
ActiveCell.Offset(0, -1).Select
Range(Selection, Selection.End(xlToLeft)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.ClearContents
End If
Okay so basically this is what I'm trying to do. I asked a question already about the first part so sorry for repeating myself but this may lend clarity to this question. Essentially, I have to create a macro that allows the user to choose a file and have it uploaded and appended to the end of a worksheet. However, the data files go in sequential order named "2015 latest.txt", "2016 latest.txt", "2017 latest.txt", etc. I need the macro to stop the data from being appended if the user uploads a file out of sequence. So if the last file uploaded was "2016 latest.txt" and they choose "2018 latest.txt" I need the data to be deleted or the file to be blocked from importing all together. I couldn't figure out how to manipulate the macro as to the name of the file (I tried using a static variable but that didn't work). Instead I just went with the data (since it lists the year) and tried naming two variables and comparing them and then deleting the data if it doesn't match. Here's my full macro:
Option Explicit
Sub ImportTextFile()
Range("A1").Select
Selection.End(xlDown).Select
ActiveCell.Offset(1, 0).Select
Dim fName As String, LastRow As Long
fName = Application.GetOpenFilename("Text Files (*.txt), *.txt")
If fName = "False" Then Exit Sub
LastRow = Range("A" & Rows.Count).End(xlUp).Row + 1
With ActiveSheet.QueryTables.Add(Connection:="TEXT;" & fName, _
Destination:=Range("A" & LastRow))
.Name = "sample"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = True
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 437
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = True
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1, 1)
.Refresh BackgroundQuery:=False
End With
Selection.EntireRow.Delete
Selection.End(xlToRight).Select
Dim Year As Integer
Year = ActiveCell.Value
ActiveCell.Offset(-1, 0).Select
Dim Year2 As Integer
Year2 = ActiveCell.Value
If Year2 <> Year + 1 Then
ActiveCell.Offset(1, 0).Select
ActiveCell.Offset(0, -1).Select
Range(Selection, Selection.End(xlToLeft)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.ClearContents
End If
End Sub

Excel macro adjust cell height

My script moves data to excel template. Codewords is changed for relevant info.
All works well if TPLNR and AUFNR is filled. The cell is two rows in height. But if i leave AUFNR or TPLNR blank - cell height not ajusted. This is macro used to fill and adjust every row in table.
Sub Mac1()
'
' Mac1
'
Dim i As Integer
i = 12
'
Do While Range("L" & i).Value <> "THE END"
If Range("L" & i).Value = "M" Then
...
ElseIf Range("L" & i).Value = "T" Then
Range("A" & i & ":D" & i).Select
With Selection
.HorizontalAlignment = xlCenter
.Orientation = 0
.WrapText = True
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = True
End With
Selection.Merge
With Selection
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlBottom
.WrapText = True
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = True
End With
Selection.Font.Italic = True
End If
i = i + 1
Loop
Call AutoFitMergedCellRowHeight
Columns("L:L").Select
Selection.Delete Shift:=xlToLeft
End Sub
Sub AutoFitMergedCellRowHeight()
Dim CurrentRowHeight As Single, MergedCellRgWidth As Single
Dim CurrCell As Range
Dim ActiveCellWidth As Single, PossNewRowHeight As Single
Dim StartCell As Range, c As Range, MergeRng As Range, Cell As Range
Dim a() As String, isect As Range, i
'Take a note of current active cell
Set StartCell = ActiveCell
'Create an array of merged cell addresses that have wrapped text
For Each c In ActiveSheet.UsedRange
If c.MergeCells Then
With c.MergeArea
If .Rows.Count = 1 And .WrapText = True Then
If MergeRng Is Nothing Then
Set MergeRng = c.MergeArea
ReDim a(0)
a(0) = c.MergeArea.Address
Else
Set isect = Intersect(c, MergeRng)
If isect Is Nothing Then
Set MergeRng = Union(MergeRng, c.MergeArea)
ReDim Preserve a(UBound(a) + 1)
a(UBound(a)) = c.MergeArea.Address
End If
End If
End If
End With
End If
Next c
Application.ScreenUpdating = False
'Loop thru merged cells
For i = 0 To UBound(a)
Range(a(i)).Select
With ActiveCell.MergeArea
If .Rows.Count = 1 And .WrapText = True Then
'Application.ScreenUpdating = False
CurrentRowHeight = .RowHeight
ActiveCellWidth = ActiveCell.ColumnWidth
For Each CurrCell In Selection
MergedCellRgWidth = CurrCell.ColumnWidth + MergedCellRgWidth
Next
.MergeCells = False
.Cells(1).ColumnWidth = MergedCellRgWidth
.EntireRow.AutoFit
PossNewRowHeight = .RowHeight
.Cells(1).ColumnWidth = ActiveCellWidth
.MergeCells = True
.RowHeight = IIf(CurrentRowHeight > PossNewRowHeight, _
CurrentRowHeight, PossNewRowHeight)
End If
End With
MergedCellRgWidth = 0
Next i
StartCell.Select
Application.ScreenUpdating = True
'Clean up
Set CurrCell = Nothing
Set StartCell = Nothing
Set c = Nothing
Set MergeRng = Nothing
Set Cell = Nothing
End Sub
What could i do to get rows after 12 to look like it intended to? With 1x height.
Making the rows equal size is quite a standard VBA task.
Just try to put this logic away from your code. The only 3 things you should know is the starting row, the ending row and the size. Thus, you may be able to do it quite well. In the code below change the parameters of Call AllRowsAreEqual(4, 10, 35) in order to make it work for you.
Option Explicit
Sub AllRowsAreEqual(lngStartRow As Long, lngEndRow As Long, lngSize)
Dim lngCounter As Long
For lngCounter = lngStartRow To lngEndRow
Cells(lngCounter, 1).RowHeight = lngSize
'Debug.Print lngCounter
Next lngCounter
End Sub
Public Sub Main()
Call AllRowsAreEqual(4, 10, 35)
End Sub

Loop code to run macro multiple times

I have this vba macro that extracts data from a text file and puts it into a column in Excel. The files are named by days (2016mmdd). Currently, I run this macro for each day. Now I want it such that when this Macro is run, the data for all the days in the declared month (say August) will be automatically extracted into different columns (a column per each day of the month). So that I won't have to manually run it 31 times if there are 31 days in the month. Thanks for helping.
Sub Macro7()
'
' Macro7 Macro
'
' Keyboard Shortcut: Ctrl+x
'
Dim fileDate, rng, rng1, rng2, rng3, rcell As String
b = InputBox("Enter file Name mmdd", "File name")
rcell = InputBox("Enter cell reference", "Reference name")
rng = "$" & rcell & "$2"
rng1 = rcell & "2:" & rcell & "14"
rng2 = rcell & "52:" & rcell & "62"
rng3 = rcell & "2:" & rcell & "101"
Filename = "j:\files\2016" & b & "2259.txt"
With ActiveSheet.QueryTables.Add(Connection:= _
"TEXT;j:\files2016" & b & "2259.txt", Destination:= _
Range(rng))
.Name = "tr" & b
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 850
.TextFileStartRow = 1
.TextFileParseType = xlFixedWidth
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = True
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(9, 1, 9)
.TextFileFixedColumnWidths = Array(103, 4)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
Range(rng1).Select
Selection.Delete Shift:=xlUp
ActiveWindow.SmallScroll Down:=45
Range(rng2).Select
Selection.Delete Shift:=xlUp
ActiveWindow.SmallScroll Down:=-60
Range(rng3).Select
End Sub
The quick approach would be to re-write Sub Macro7() to accept parameters, e.g.
Sub ImportFiles(FName As String, ColNum As Integer)
' blablabla
' work with range objects ... not with patched strings containing range addresses
Dim Rng As Range, Rng1 As Range, Rng2 As Range, Rng3 As Range
Set Rng = Cells(2, ColNum)
Set Rng1 = Range(Cells(2, ColNum), Cells(14, ColNum))
Set Rng2 = Range(Cells(52, ColNum), Cells(62, ColNum))
Set Rng3 = Range(Cells(2, ColNum), Cells(101, ColNum))
Filename = "j:\files\2016" & FName & "2259.txt"
' and replace <Destination := Range(Rng)> by <Destination := Rng>
' blablabla
' use the range objects defined/set earlier ... save on Select/Selection
Rng1.Delete xlUp
Rng2.Delete xlUp
Rng3.Select
End Sub
and have a calling Macro e.g.
Sub DoWorklist()
ImportFiles "0901", 1
ImportFiles "0902", 2
ImportFiles "0903", 3
' blablabla
'alternative
Dim Idx As Integer
For Idx = 1 To 30
' to overcome well spotted chr() issue we convert running number Idx
' into 2 digit string with leading "0"
ImportFiles "09" & Format(Idx, "00"), Idx
Next Idx
End Sub

VBA Stock info retrieval into Excel

first off, I have to admit I'm not very good at VBA. I've tried to adapt the code from this and this site to download the information I need on a list of given stock tickers. I have a list of the tickers in column A of sheet "data" and want the downloaded infos (name, exchange, bid, ask, etc.) in the columns to the right, starting in column c. I want to run the macro (and thus update all values) with a click on a button.
I tried to adapt the code accordingly but keep on running into errors I cannot debug. Can you experts help me get the code right?
Thanks so much in advance!
Error
Sub DownloadStockQuotes(ByVal stockTicker As String, ByVal DestinationCell As String)
Dim qurl As String
Dim StartMonth, StartDay, StartYear, EndMonth, EndDay, EndYear As String
Dim C As WorkbookConnection
StartMonth = Format(Month(StartDate) - 1, "00")
StartDay = Format(Day(StartDate), "00")
StartYear = Format(Year(StartDate), "00")
EndMonth = Format(Month(EndDate) - 1, "00")
EndDay = Format(Day(EndDate), "00")
EndYear = Format(Year(EndDate), "00")
qurl = "URL;http://finance.yahoo.com/d/quotes.csv?s=" + stockTicker + "&f=nxj1b4abc1p2"
On Error GoTo ErrorHandler:
With ActiveSheet.QueryTables.Add(Connection:=qurl, Destination:=Range(DestinationCell))
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
' .PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
' .RefreshPeriod = 0
' .WebSelectionType = xlSpecifiedTables
' .WebFormatting = xlWebFormattingNone
' .WebTables = "20"
' .WebPreFormattedTextToColumns = True
' .WebConsecutiveDelimitersAsOne = True
' .WebSingleBlockTextImport = False
' .WebDisableDateRecognition = False
' .WebDisableRedirections = False
.Refresh BackgroundQuery:=False
End With
ErrorHandler:
End Sub
Sub DownloadData()
Dim frequency As String
Dim numRows As Integer
Dim lastRow As Integer
Dim lastErrorRow As Integer
Dim lastSuccessRow As Integer
Dim stockTicker As String
Application.ScreenUpdating = False
lastRow = Worksheets("Kursabruf").Cells(Rows.Count, "a").End(xlUp).Row
'Loop through all tickers
For ticker = 2 To lastRow
stockTicker = Worksheets("Kursabruf").Range("$a$" & ticker)
If stockTicker = "" Then
GoTo NextIteration
End If
Call DownloadStockQuotes(stockTicker, "$c$2")
Worksheets("Kursabruf").Columns("c:c").TextToColumns Destination:=Range("c2"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
DecimalSeparator:=".", ThousandsSeparator:=" ", _
Semicolon:=False, Comma:=True, Space:=False, Other:=False, FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1), Array(4, 1), Array(5, 1), Array(6, 1), Array(7, 1))
Sheets(stockTicker).Columns("A:G").ColumnWidth = 10
lastRow = Sheets(stockTicker).UsedRange.Row - 2 + Sheets(stockTicker).UsedRange.Rows.Count
GoTo NextIteration
'Delete final blank row otherwise will get ,,,, at bottom of CSV
Sheets("Kursabruf").Rows(lastRow + 1 & ":" & Sheets("Kursabruf").Rows.Count).Delete
NextIteration:
Next ticker
Application.DisplayAlerts = False
ErrorHandler:
Worksheets("Parameters").Select
For Each C In ThisWorkbook.Connections
C.Delete
Next
End Sub