Improve Speed of VBA Cells.Find Loop - performance

I'm new to writing Macros and would love some help improving the speed on this one.
I have a sheet with 35,000+ rows, and I'm looping through it to find each instance of a value (OldSKU), grabbing the SKUSubset data associated with it (which has a variable number of rows), and pasting it into a new sheet (SubsetImporter) at the first empty row.
Right now, it can take 5 minutes to loop through and find all the instances of a SKU that shows up multiple times.
OldSKU will only ever show up in Column B. Is there a way to improve the speed of this loop? Possibly defining the range that it should search through?
Sub UpdateSKU()
Dim OldSKU As Long
Dim NewSKU As Long
Dim SKUSubset As String
Dim SubsetRange As Range
Dim aPlace As Range
Dim bPlace As Range
Dim SubsetPastePlace As Long
OldSKU = Sheets("Rollover Request").Range("A2")
NewSKU = Sheets("Rollover Request").Range("B2")
'UPDATE SUBSET IMPORTER
Sheets("Subset Exporter").Activate
Set aPlace = Cells.Find(What:=OldSKU, After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
SKUSubset = Cells.Find(What:=OldSKU, After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Offset(0, -1).Value
Set bPlace = aPlace
Set aPlace = Cells.Find(What:=OldSKU, After:=aPlace, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
Range("A1", Cells(1, 1).SpecialCells(xlLastCell)).AutoFilter Field:=1, Criteria1:=SKUSubset
Range(ActiveSheet.UsedRange.SpecialCells(xlLastCell), Cells(2, 1)).Copy
SubsetPastePlace = Sheets("Subset Importer").Cells(Rows.Count, 1).End(xlUp).Offset(1).Row
Sheets("Subset Importer").Range("A" & SubsetPastePlace).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
Sheets("Subset Exporter").Activate
Sheets("Subset Exporter").Range("A2").Select
Sheets("Subset Exporter").ShowAllData
If bPlace.Row < aPlace.Row Then
Do
SKUSubset = aPlace.Offset(0, -1).Value
Range("A1", Cells(1, 1).SpecialCells(xlLastCell)).AutoFilter Field:=1, Criteria1:=SKUSubset
Range(ActiveSheet.UsedRange.SpecialCells(xlLastCell), Cells(2, 1)).Copy
SubsetPastePlace = Sheets("Subset Importer").Cells(Rows.Count, 1).End(xlUp).Offset(1).Row
Sheets("Subset Importer").Range("A" & SubsetPastePlace).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
Sheets("Subset Exporter").Activate
Worksheets("Subset Exporter").ShowAllData
Set bPlace = aPlace
Set aPlace = Cells.Find(OldSKU, After:=aPlace, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
Loop Until aPlace.Row < bPlace.Row
End If
End Sub

Lightly-tested:
Sub UpdateSKU()
Dim OldSKU As Long
Dim NewSKU As Long
Dim SKUSubset As String
Dim SubsetRange As Range
Dim skuCells As Collection, shtExp As Worksheet, shtImp As Worksheet
Dim skuCell
Set shtExp = Sheets("Subset Exporter")
Set shtImp = Sheets("Subset Importer")
OldSKU = Sheets("Rollover Request").Range("A2")
NewSKU = Sheets("Rollover Request").Range("B2")
Set skuCells = FindAll(shtExp.Columns(2), OldSKU) 'get all instances of SKU
shtExp.Activate
For Each skuCell In skuCells
SKUSubset = skuCell.Offset(0, -1).Value
shtExp.Range("A1", Cells(1, 1).SpecialCells(xlLastCell)).AutoFilter _
Field:=1, Criteria1:=SKUSubset
shtExp.Range(shtExp.Cells(2, 1), shtExp.UsedRange. _
SpecialCells(xlLastCell)).Copy
shtImp.Cells(Rows.Count, 1).End(xlUp).Offset(1).PasteSpecial _
Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False
shtExp.ShowAllData
Next skuCell
End Sub
'return a Collection containing all cells with value [findWhat]
Function FindAll(rngToSearch As Range, findWhat As Long) As Collection
Dim rv As New Collection, f As Range, add1 As String
Set f = rngToSearch.Find(what:=findWhat, LookIn:=xlValues, Lookat:=xlWhole)
If Not f Is Nothing Then
add1 = f.Address()
Do While Not f Is Nothing
rv.Add f
Set f = rngToSearch.FindNext(after:=f)
If f.Address = add1 Then Exit Do
Loop
End If
Set FindAll = rv
End Function

Related

Append To next row excel VBA

This program is working fine I just want to append my tag to next row without any limit.
Sub ExportExcel(ByVal Atai)
Dim a
Set a = CreateObject("Excel.Application")
a.Visible = True
a.Workbooks.Open "C:\Users\Muhammad Awais\Desktop\start and stop data logging\POWER METER 1.xls"
**
**a.Sheets("raw data").Cells(3, 4).Value = SmartTags("l1-l2")
a.Sheets("raw data").Cells(4, 4).Value = SmartTags("l2-l3")
****
a.ActiveWorkbook.SaveAs "C:\Users\Muhammad Awais\Desktop\start and stop data logging\"&Day(Date)& ("_") &Month(Date)& ("_") &Year(Date)& ("_") &Hour(Time)&Minute(Time)&".xls"
a.Workbooks.Close
a.Quit
Set a = Nothing
End Sub
LastRow = sh.Cells.Find(What:="*", _
After:=a.Sheets("raw data").Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row

Taking too long to clear table, copy from another workbook, paste, and autofill formulas

In my master workbook I have 1 table in each one of my 4 sheets and in sheet2 and sheet4 I have a couple of columns with IF and VLOOKUP functions at the right of the table.
I am trying to do the following:Clear content from the 4 tables while maintaining only one row of formulas (in sheet 2 and 4), Copy the range I want from a table in sheet1 of another workbook (repeat for other sheets), And paste into the table of sheet1 of master workbook (repeat for other sheets), Autofill the formulas of the remanining columns (only in sheet 2 and 4).
While the code does it's job, it takes almost 2 hours to perform this task! Even the Clearcontent of sheet2 takes 8 minutes for just 250 rows which seems ridiculous long time! Sheet1 has 1000 rows, sheet2 has 250, sheet3 has 1000, sheet4 has 26k rows.
Code seems too big for what it does. What can I do to optimise and speed up the code? Any viable work around or is this normal? I have tried Application.Calculation = xlCalculationManual but no improvement.
Sub LoopThroughDirectory()
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Dim MyFile As String
Dim erow1
Dim erow2
Dim erow3
Dim erow4
Dim Filepath As String
Dim wkb As Workbook
Dim sht1 As Worksheet
Dim sht2 As Worksheet
Dim sht3 As Worksheet
Dim sht4 As Worksheet
Dim ero2 As Long
Dim ero4 As Long
Dim lastero1 As Long
Dim lastero2 As Long
Dim lastero3 As Long
Dim lastero4 As Long
Folha1.Activate
Folha1.Range(Cells(3, 1), Cells(99999, 173)).ClearContents
Folha1.Range(Cells(2, 1), Cells(99999, 173)).ClearContents
Folha2.Activate
Folha2.Range(Cells(3, 1), Cells(99999, 150)).ClearContents
Folha2.Range(Cells(2, 1), Cells(99999, 137)).ClearContents
Folha3.Activate
Folha3.Range(Cells(3, 1), Cells(99999, 197)).ClearContents
Folha3.Range(Cells(2, 1), Cells(99999, 197)).ClearContents
Folha4.Activate
Folha4.Range(Cells(3, 1), Cells(99999, 152)).ClearContents
Folha4.Range(Cells(2, 1), Cells(99999, 108)).ClearContents
Filepath = "C:\Users\carlos\Downloads\Projectos\Teste\"
MyFile = Dir(Filepath)
Do While MyFile = "Dados Projectos New"
If MyFile = "Dados Projectos_Master.xlsm" Then
Exit Sub
End If
Set wkb = Workbooks.Open(Filepath & MyFile)
Set sht1 = wkb.Sheets("Encomendas")
Set sht2 = wkb.Sheets("Projectos")
Set sht3 = wkb.Sheets("Casos")
Set sht4 = wkb.Sheets("Actividades Serviço")
wkb.Activate
sht1.Activate
With Sheets("Encomendas") 'Last row of the first sheet I want to copy
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
lastero1 = .Range("A:fq").Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
End If
End With
Range("a2:fq" & lastero1).Copy
Folha1.Activate
'last row of the first sheet of master workbook I want to paste
erow1 = Folha1.Cells.Find("*", After:=Range(Cells(Rows.Count, 173), Cells(Rows.Count, 173)), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
ThisWorkbook.ActiveSheet.Paste Destination:=Worksheets("Encomendas").Range(Cells(erow1 + 1, 1), Cells(erow1 + 1, 173))
wkb.Activate
sht2.Activate
With Sheets("Projectos") 'Last row of the second sheet I want to copy
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
lastero2 = .Range("A:EG").Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
End If
End With
Range("a2:Eg" & lastero2).Copy
Folha2.Activate
With Sheets("Projectos") 'Last row of the second sheet of master workbook I want to paste
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
erow2 = .Range("A:EG").Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
End If
End With
ThisWorkbook.ActiveSheet.Paste Destination:=Worksheets("Projectos").Range(Cells(erow2 + 1, 1), Cells(erow2 + 1, 137))
With Sheets("Projectos") 'Last row of the second sheet of master workbook I want to autofill
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
ero2 = .Range("A:EG").Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
End If
End With
Range("EH2:ET2").AutoFill Destination:=Range("EH2:ET" & ero2)
wkb.Activate
sht3.Activate
With Sheets("Casos") 'Last row of the third sheet I want to copy
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
lastero3 = .Range("A:go").Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
End If
End With
Range("a2:go" & lastero3).Copy
'Last row of the third sheet of master workbook I want to paste
erow3 = Folha3.Cells.Find("*", After:=Range(Cells(Rows.Count, 197), Cells(Rows.Count, 197)), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Folha3.Activate
ThisWorkbook.ActiveSheet.Paste Destination:=Worksheets("Casos").Range(Cells(erow3 + 1, 1), Cells(erow3 + 1, 197))
wkb.Activate
sht4.Activate
With Sheets("Actividades Serviço") 'Last row of the fourth sheet I want to copy
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
lastero4 = .Range("A:dd").Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
End If
End With
Range("a2:dd" & lastero4).Copy
ActiveWorkbook.Close
Folha4.Activate
With Sheets("Actividades serviço") 'Last row of the fourth sheet of master workbook I want to paste
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
erow4 = .Range("A:DD").Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
End If
End With
ThisWorkbook.ActiveSheet.Paste Destination:=Worksheets("Actividades serviço").Range(Cells(erow4 + 1, 1), Cells(erow4 + 1, 108))
With Sheets("Actividades serviço") 'Last row of the fourth sheet of master workbook I want to autofill
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
ero4 = .Range("A:DD").Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
End If
End With
Range("de2:EV2").AutoFill Destination:=Range("de2:Ev" & ero4)
MyFile = Dir
Loop
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Issues I see so far:
Folha1.Activate
Folha1.Range(Cells(3, 1), Cells(99999, 173)).ClearContents
Folha1.Range(Cells(2, 1), Cells(99999, 173)).ClearContents
You don’t need to activate since youre quite literally telling it where to clear contents.
Range("a2:fq" & lastero1).Copy
No need to copy, you can literally saying something like “Range(“a1”).Value = Range(“C2”).Value. This also means by extension that you don’t have to paste as well.
Some of the major performance tips for macros suggest not to “Copy/Paste” as well as try to avoid “selecting” and “activating.” In fact, directly manipulating worksheets is often seen as cardinal sin.
With larger data sets that need to be moved around, storing everything in an array before dumping to new locations also saves big on time.
Hopes this helps.

populating a matrix in vba

I'm trying to populate a matrix from three columns in a worksheet. My code is supposed to find a value in the first column, match it to the y-axis, then search the second column for a value, match it to a column header in the x-axis, and then paste the value from the third column in the cell activated by the row/column match. Does anyone see what's wrong with my code? I keep getting a "object variable or with block variable not set" error:
Sub Button1_Click()
Application.ScreenUpdating = False
Dim filePath As String
Dim strDate As String
Dim strMatchJE As String
Dim strMatchComponent As String
Dim wSheet As Worksheet
Dim wBook1 As Workbook
Set wSheet = ThisWorkbook.Sheets("Sheet1")
'Activate Journal Entry Number
strMatchJE = Columns("A").Find(what:="", after:=wSheet.Cells(1, 1), LookIn:=xlValues).Activate
aString = Left(originalString, 1)
strMatchJE = wSheet.Cells.Find(what:=aString, after:=Wbook.Cells(1, 1), _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=True).Address
'Activate component
strMatchComponent = Columns("B").Find(what:="", after:=wSheet.Cells(1, 1), LookIn:=xlValues).Activate
bString = Left(originalString, 1)
strMatchJE = wSheet.Cells.Find(what:=aString, after:=Wbook.Cells(2, 1), _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByColumns, _
SearchDirection:=xlNext, MatchCase:=True).Address
strEnterAmount = Columns("T").Find(what:="", after:=wSheet.Cells(3, 1), LookIn:=xlValues).Activate
firstrow = ActiveCell.Row
firstcolumn2 = ActiveCell.Column
firstrow = firstrow + 1
Rows(firstrow).Columns(firstcolumn2).Select
strEnterAmount.Paste
End Sub

VBA : Find function code

I am trying to do vlookup through the find function in vba. I have a list of numbers in loan sheet and property sheet and If the number is found in the loan sheet then it copies the entire row and pastes it in another sheet called query. This is the code I have currently but the code just hangs as I have too many cells to find around 100,000. Any guidance in any errors in the code would be really helpful.
Option Explicit
Sub FindCopy_lall()
Dim calc As Long
Dim Cel As Range
Dim LastRow As Long
Dim LastRow2 As Long
Dim rFound As Range
Dim LookRange As Range
Dim CelValue As Variant
' Speed
calc = Application.Calculation
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
'Get Last row of Property SheetColumn
LastRow = Worksheets("Property").Cells(Rows.Count, "E").End(xlUp).Row
LastRow2 = Worksheets("Loan").Cells(Rows.Count, "D").End(xlUp).Row
' Set range to look in
Set LookRange = Worksheets("Property").Range("E2:E" & LastRow)
' Loop on each value (cell)
For Each Cel In LookRange
' Get value to find
CelValue = Cel.Value
' Look on IT_Asset
' With Worksheets("Loan")
' Allow not found error
On Error Resume Next
Set rFound = Worksheets("Loan").Range("D2:D" & LastRow2).Find(What:=CelValue, _
LookIn:=xlValues, _
Lookat:=xlWhole, MatchCase:=False)
' Reset
On Error GoTo endo
' Not found, go next
If rFound Is Nothing Then
GoTo nextCel
Else
Worksheets("Loan").Range("rFound:rFound").Select
Selection.Copy
Worksheets("Query").Range("Cel:Cel").Select
ActiveSheet.Paste
End If
'End With
nextCel:
Next Cel
'Reset
endo:
With Application
.Calculation = calc
.ScreenUpdating = True
End With
End Sub
Running Find() many times in a loop can be very slow - I usually create a lookup using a Dictionary: typically thus is much faster and makes the loop easier to code.
Sub FindCopy_lall()
Dim calc As Long
Dim Cel As Range, LookRange As Range
Dim LastRow As Long
Dim LastRow2 As Long
Dim CelValue As Variant
Dim dict As Object
calc = Application.Calculation
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
LastRow = Worksheets("Property").Cells(Rows.Count, "E").End(xlUp).Row
LastRow2 = Worksheets("Loan").Cells(Rows.Count, "D").End(xlUp).Row
Set dict = RowMap(Worksheets("Loan").Range("D2:D" & LastRow2))
Set LookRange = Worksheets("Property").Range("E2:E" & LastRow)
For Each Cel In LookRange
CelValue = Cel.Value
If dict.exists(CelValue) Then
'just copy values (5 cols, resize to suit)
Cel.Offset(0, 1).Resize(1, 5).Value = _
dict(CelValue).Offset(0, 1).Resize(1, 5).Value
'...or copy the range
'dict(CelValue).Offset(0, 1).Resize(1, 5).Copy Cel.Offset(0, 1)
End If
Next Cel
With Application
.Calculation = calc
.ScreenUpdating = True
End With
End Sub
'map a range's values to their respective cells
Function RowMap(rng As Range) As Object
Dim rv As Object, c As Range, v
Set rv = CreateObject("scripting.dictionary")
For Each c In rng.Cells
v = c.Value
If Not rv.exists(v) Then
rv.Add v, c
Else
MsgBox "Duplicate value detected!"
Exit For
End If
Next c
Set RowMap = rv
End Function
There are many things that needs to be re-written
A) Variables inside the quotes become a string. For example "rFound:rFound" Also you do not need to specify Worksheets("Loan"). before it. It is understood.
You can simply write it as rFound.Select
B) Avoid the Use of .Select It slows down the code. You might want to see this LINK. For example
Worksheets("Loan").Range("rFound:rFound").Select
Selection.Copy
Worksheets("Query").Range("Cel:Cel").Select
ActiveSheet.Paste
The above can be written as
rFound.Copy Cel
Work with Variables/Objects. Try and ignore the use of On Error Resume Next and unnecessary GO TOs if possible.
Try this (UNTESTED)
Option Explicit
Sub FindCopy_lall()
Dim calc As Long, LrowWsI As Long, LrowWsO As Long
Dim Cel As Range, rFound As Range, LookRange As Range
Dim wsI As Worksheet, wsO As Worksheet
calc = Application.Calculation
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
Set wsI = ThisWorkbook.Sheets("Property")
Set wsO = ThisWorkbook.Sheets("Loan")
LrowWsI = wsI.Range("E" & wsI.Rows.Count).End(xlUp).Row
LrowWsO = wsO.Range("D" & wsI.Rows.Count).End(xlUp).Row
Set LookRange = wsI.Range("E2:E" & LrowWsI)
For Each Cel In LookRange
Set rFound = wsO.Range("D2:D" & LrowWsO).Find(What:=Cel.Value, _
LookIn:=xlValues, Lookat:=xlWhole, MatchCase:=False)
If Not rFound Is Nothing Then
'~~> You original code was overwriting the cel
'~~> I am writing next to it. Chnage as applicable
rFound.Copy Cel.Offset(, 1)
End If
Next Cel
With Application
.Calculation = calc
.ScreenUpdating = True
End With
End Sub
Besides the possible bugs the two big performance issues are
doing an Excel .Find.. inside your loop over all your source rows, which as has already been noted, is very slow. And
actually cutting and pasting a lot of rows is also pretty slow. If you only care about the values, then you can use range-array data copies instead which are very fast.
This is how I would do it, which should be very fast:
Option Explicit
Option Compare Text
Sub FindCopy_lall()
Dim calc As Long, CelValue As Variant
Dim LastRow As Long, LastRow2 As Long, r As Long, sr As Long
Dim LookRange As Range, FindRange As Range, rng As Range
Dim LastLoanCell As Range, LastLoanCol As Long
Dim rowVals() As Variant
' Speed
calc = Application.Calculation
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
'capture the worksheet objects
Dim wsProp As Worksheet: Set wsProp = Worksheets("Property")
Dim wsLoan As Worksheet: Set wsLoan = Worksheets("Loan")
Dim wsQury As Worksheet: Set wsQury = Worksheets("Query")
'Get Last row of Property SheetColumn
LastRow = wsProp.Cells(Rows.Count, "E").End(xlUp).Row
LastRow2 = wsLoan.Cells(Rows.Count, "D").End(xlUp).Row
Set LastLoanCell = wsLoan.Cells.SpecialCells(xlCellTypeLastCell)
LastLoanCol = LastLoanCell.Column
' Set range to look in; And get it's data
Set LookRange = wsProp.Range("E2:E" & LastRow)
Dim Look() As Variant: ReDim Look(2 To LastRow, 1 To 1)
Look = LookRange
' Index the source values
Dim colIndex As New Collection
For r = 2 To UBound(Look, 1)
' ignore duplicate key errors
On Error Resume Next
colIndex.Add r, CStr(CelValue)
On Error GoTo endo
Next
'Set the range to search; and get its data
Set FindRange = wsLoan.Range("D2:D" & LastRow2)
Dim Find() As Variant: ReDim Find(2 To LastRow2, 1 To 1)
Find = FindRange
' Loop on each value (cell) in the Find range
For r = 2 To UBound(Find, 1)
'Try to find it in the Look index
On Error Resume Next
sr = colIndex(CStr(CelValue))
If Err.Number = 0 Then
'was found in index, so copy the row
On Error GoTo endo
' pull the source row values into an array
Set rng = wsLoan.Range(wsLoan.Cells(r, 1), wsLoan.Cells(r, LastLoanCol))
ReDim rowVals(1 To rng.Rows.Count, 1 To rng.Columns.Count)
rowVals = rng
' push the values out to the target row
Set rng = wsQury.Range(wsQury.Cells(sr, 1), wsQury.Cells(sr, LastLoanCol))
rng = rowVals
End If
On Error GoTo endo
Next r
endo:
'Reset
Application.Calculation = calc
Application.ScreenUpdating = True
End Sub
As others have noted, we cannot tell from your code where the output rows are actually supposed to go on the Query sheet, so I made a guess, but you made need to change that.

Write text file in appending (utf-8 encoded) in VB6

I have to write a textfile in VB6. I need to do it in appending and utf-8 encoded.
I tried two solutions, one with "TextStream" and another one with "ADODB.Stream".
The first one:
Set fsoFile = fso.OpenTextFile(FileIn(fi), ForAppending, True)
fsoFile.WriteLine "<tag>kkkjòòkkkkjlòlk</tag>"
fsoFile.Close
Works good in appending but how can I write it utf-8 encoded?
The second one:
Dim ST As ADODB.Stream
Set ST = New ADODB.Stream
ST.Mode = adModeReadWrite
ST.Type = adTypeText
ST.Charset = "UTF-8"
ST.Open
ST.LoadFromFile FileIn(fi)
ST.Position = ST.Size
ST.WriteText "<tag>kkkjòòkkkkjlòlk</tag>"
ST.SaveToFile FileIn(fi)
ST.Close
Write correctly in utf-8 but I can't write the file in appending but only with "adSaveCreateOverWrite".
How can I do that? Is there another way?
Thank you very much.
You could combine binary I/O with an API call to perform the conversion to UTF-8:
Option Explicit
Private Const CP_UTF8 As Long = 65001
Private Declare Function WideCharToMultiByte Lib "kernel32" ( _
ByVal CodePage As Long, _
ByVal dwFlags As Long, _
ByVal lpWideCharStr As Long, _
ByVal cchWideChar As Long, _
ByVal lpMultiByteStr As Long, _
ByVal cchMultiByte As Long, _
ByVal lpDefaultChar As Long, _
ByVal lpUsedDefaultChar As Long) As Long
Private Function OpenAppendUTF8(ByVal FileName As String) As Integer
OpenAppendUTF8 = FreeFile(0)
Open FileName For Binary Access Write As #OpenAppendUTF8
Seek #OpenAppendUTF8, LOF(OpenAppendUTF8) + 1
End Function
Private Sub WriteUTF8( _
ByVal FNum As Integer, _
ByVal Text As String, _
Optional ByVal NL As Boolean)
Dim lngResult As Long
Dim UTF8() As Byte
If NL Then Text = Text & vbNewLine
lngResult = WideCharToMultiByte(CP_UTF8, 0, StrPtr(Text), Len(Text), _
0, 0, 0, 0)
If lngResult > 0 Then
ReDim UTF8(lngResult - 1)
WideCharToMultiByte CP_UTF8, 0, StrPtr(Text), Len(Text), _
VarPtr(UTF8(0)), lngResult, 0, 0
Put #FNum, , UTF8
End If
End Sub
Private Sub Main()
Dim F As Integer
F = OpenAppendUTF8("test.txt")
WriteUTF8 F, "Hello"
WriteUTF8 F, ChrW$(&H2026&)
WriteUTF8 F, "World", True
Close #F
MsgBox "Done"
End Sub
I prefer to save it ANSI as it does by default. Open it with a notepad and overwrite it selecting UTF8 encoding. I found it's the fastest way by far.
And I use some other code to append, for example for a database convertion:
Dim fs As Object, a
Set fs = CreateObject("Scripting.FileSystemObject")
Set a = fs.CreateTextFile(filename, True) 'example (myfile.xml, True)
a.writeline var1
a.writeline var2
a.Close
Actually no need for API call.
Option Explicit
Sub testAppend()
Dim fileName
fileName = "C:\Test\test.txt"
Dim f As Integer
f = FreeFile(0)
Open fileName For Binary Access Write As #f
Seek #f, LOF(f) + 1
Dim t
t = "<tag>" & ChrW(107) & ChrW(107) & ChrW(107) & ChrW(106) & ChrW(242) & ChrW(242) & ChrW(107) & ChrW(107) & ChrW(107) & ChrW(107) & ChrW(106) & ChrW(108) & ChrW(242) & ChrW(108) & ChrW(107) & "</tag>"
Put #f, , textToBinary(t, "utf-8")
Close #f
End Sub
Function textToBinary(text, charset) As Byte()
With CreateObject("ADODB.Stream")
.Open
.Type = 2 ' adTypeText
.charset = charset
.WriteText text
.Position = 0
.Type = 1 ' adTypeBinary
textToBinary = .Read
.Close
End With
End Function```

Resources