I am trying to merge data from particular columns from multiple csv files. This thread: Excel VBA - Merge specific columns from multiple files to one sheet worked for whole ranges of columns. However, I want to copy e.g. each 100th cell from particular column (instead of whole column as it is at the moment).
I have tried to modify the code as per below method 1 and 2 (see **** notes).
This VBA is to go through datalog files which have time stamps in rows and parameters for each time stamp. However, I don't want all parameters, only selected ones (per columns) and in each 100th row.
'takes worksheet and returns last row
Private Function LastRowUsed(sh As Worksheet) As Long
On Error Resume Next
LastRowUsed = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
'takes worksheet and returns last column
Private Function LastColUsed(sh As Worksheet) As Long
On Error Resume Next
LastColUsed = sh.Cells.Find(What:="*", _
After:=sh.Range(A1), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
On Error GoTo 0
End Function
'takes worksheet and returns last row in column
Private Function LastRowUsedbyCol(sh As Worksheet, ByVal Col As String) As Long
On Error Resume Next
LastRowUsed = sh.Cells.Find(What:="*", _
After:=sh.Range(Cell(Col, 1), Cell(Col, 1)), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
Function GetFileListArray() As String()
Dim fileDialogBox As FileDialog
Dim SelectedFolder As Variant
Dim MYPATH As String
Dim MYFILES() As String
Dim FILESINPATH
Dim FNUM, i As Integer
'''''
Set fileDialogBox = Application.FileDialog(msoFileDialogFolderPicker)
'Use a With...End With block to reference the FileDialog object.
With fileDialogBox
If .Show = -1 Then 'the user chose a folder
For Each SelectedFolder In .SelectedItems
MYPATH = SelectedFolder 'asign mypath to the selected folder name
'MsgBox "The path is:" & SelectedFolder, vbInformation 'display folder selected
Next SelectedFolder
'The user pressed Cancel.
Else
MsgBox "Cancel was pressed or Invalid folder chosen, ending macro"
Exit Function
End If
End With
'Set the file dialog object variable to Nothing to clear memory
Set fileDialogBox = Nothing
If Right(MYPATH, 1) <> "\" Then
MYPATH = MYPATH & "\"
End If
FILESINPATH = Dir(MYPATH & "*.csv")
'MsgBox FILESINPATH
If FILESINPATH = "" Then
MsgBox "No files found"
Exit Function
End If
'Fill the array(myFiles)with the list of Excel files in the folder
FNUM = 0
Do While FILESINPATH <> ""
FNUM = FNUM + 1
ReDim Preserve MYFILES(1 To FNUM)
MYFILES(FNUM) = MYPATH & FILESINPATH
FILESINPATH = Dir()
Loop
GetFileListArray = MYFILES()
End Function
Sub RFSSearchThenCombine()
'search first worksheet in files opened, change to search other worksheets
Const SHEET_TO_SEARCH = 1
Dim FileList() As String
Dim CurrentFolder As String
Dim openedWorkBook As Workbook, HeadingWorkbook As Workbook
Dim OpenedWorkSheet As Worksheet, HeadingWorkSheet As Worksheet
Dim i, counter, x, j As Integer
Dim LRowHeading, LRowOpenedBook, LColHeading, LColOpenedBook, LRowHeadingC As Long
Dim dict As dictionary
Dim searchValue
'set original workbook with headings to retrieve
Set HeadingWorkbook = ActiveWorkbook
Set HeadingWorkSheet = HeadingWorkbook.Sheets(1)
'find last column on heading worksheet
LColHeading = LastColUsed(HeadingWorkSheet)
'create dictionary to link headers to position in heading worksheet
Set dict = CreateObject("Scripting.Dictionary")
For x = 1 To LColHeading
dict.Add HeadingWorkSheet.Cells(1, x).Value, x
Next x
FileList() = GetFileListArray()
For counter = 1 To UBound(FileList)
Set openedWorkBook = Workbooks.Open(FileList(counter))
Set OpenedWorkSheet = openedWorkBook.Sheets(SHEET_TO_SEARCH)
LColOpenedBook = LastColUsed(openedWorkBook.Sheets(1))
LRowOpenedBook = LastRowUsed(openedWorkBook.Sheets(1))
LRowHeading = LastRowUsed(HeadingWorkSheet)
For i = 1 To LColOpenedBook 'search headers from a1 to last header
searchValue = OpenedWorkSheet.Cells(1, i).Value 'set search value in to current header
If dict.Exists(searchValue) Then
' *** code from previous thread
'OpenedWorkSheet.Range(OpenedWorkSheet.Cells(1, i), _
'OpenedWorkSheet.Cells(LRowOpenedBook, i)).Copy _
'(HeadingWorkSheet.Cells(LRowHeading, dict.Item(searchValue)))
'**** my proposal
For j = 1 To LRowOpenedBook Step 100
OpenedWorkSheet.Range(OpenedWorkSheet.Cells(j, i), _
OpenedWorkSheet.Cells(j, i)).Copy _
(HeadingWorkSheet.Cells(LRowHeading + 1, dict.Item(searchValue)))
LRowHeading = LRowHeading + 1
'**** my 2nd proposal
'LRowHeadingC = HeadingWorkSheet.Cells(Rows.Count, i).End(xlUp).Row
'For j = 1 To LRowOpenedBook Step 100
' OpenedWorkSheet.Range(OpenedWorkSheet.Cells(j, i), _
'OpenedWorkSheet.Cells(j, i)).Copy _
'(HeadingWorkSheet.Cells(LRowHeadingC + 1, dict.Item(searchValue)))
'LRowHeadingC = LRowHeadingC + 1
Next j
End If
Next i
openedWorkBook.Close (False)
Next counter ' move on to next file
End Sub
1st method (when working) results in shift of rows from next columns (all pasted data start from last row (not last row in particular column), it more less results in below pattern (where cl is for column and x represents data):
cl1 cl2 cl3 cl3
x
x
x
x
x
x
x
x
x x
x
x
x
x
x
While I want to receive below pattern:
cl1 cl2 cl3 cl3
x x x x
x x x x
x x x x
Another question is how should I modify function: LastRowUsed not to start from A1, but e.g. from B1, etc.? I tried to resolve that with Method 2.
Based on feedback above I have changed the loops order and that made it work. I have also polished the code (copying from range to range and added option explicit). Code does the job now.
Now I will be trying to change it to more efficient version (it takes plenty of time with few hundreds of workbooks). At the moment I am copying and pasting each cell individually between workbooks. I think that a set of cells (e.g. multiple selection of each 100th cell) would be quicker.
Or building an array of values needed and pasting array into headingsWorkbook as range.
Here is how the code looks now:
Option Explicit
'takes worksheet and returns last row
Private Function LastRowUsed(sh As Worksheet) As Long
On Error Resume Next
LastRowUsed = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
'takes worksheet and returns last column
Private Function LastColUsed(sh As Worksheet) As Long
On Error Resume Next
LastColUsed = sh.Cells.Find(What:="*", _
After:=sh.Range(A1), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
On Error GoTo 0
End Function
'takes worksheet and returns last row in column
Private Function LastRowUsedbyCol(sh As Worksheet, ByVal Col As String) As Long
On Error Resume Next
LastRowUsed = sh.Cells.Find(What:="*", _
After:=sh.Range(Cell(Col, 1), Cell(Col, 1)), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
Function GetFileListArray() As String()
Dim fileDialogBox As FileDialog
Dim SelectedFolder As Variant
Dim MYPATH As String
Dim MYFILES() As String
Dim FILESINPATH
Dim FNUM, i As Integer
'''''
Set fileDialogBox = Application.FileDialog(msoFileDialogFolderPicker)
'Use a With...End With block to reference the FileDialog object.
With fileDialogBox
If .Show = -1 Then 'the user chose a folder
For Each SelectedFolder In .SelectedItems
MYPATH = SelectedFolder 'asign mypath to the selected folder name
'MsgBox "The path is:" & SelectedFolder, vbInformation 'display folder selected
Next SelectedFolder
'The user pressed Cancel.
Else
MsgBox "Cancel was pressed or Invalid folder chosen, ending macro"
Exit Function
End If
End With
'Set the file dialog object variable to Nothing to clear memory
Set fileDialogBox = Nothing
If Right(MYPATH, 1) <> "\" Then
MYPATH = MYPATH & "\"
End If
FILESINPATH = Dir(MYPATH & "*.csv")
'MsgBox FILESINPATH
If FILESINPATH = "" Then
MsgBox "No files found"
Exit Function
End If
'Fill the array(myFiles)with the list of Excel files in the folder
FNUM = 0
Do While FILESINPATH <> ""
FNUM = FNUM + 1
ReDim Preserve MYFILES(1 To FNUM)
MYFILES(FNUM) = MYPATH & FILESINPATH
FILESINPATH = Dir()
Loop
GetFileListArray = MYFILES()
End Function
Sub RFSSearchThenCombineEach1000thRow()
'search first worksheet in files opened, change to search other worksheets
Const SHEET_TO_SEARCH = 1
Dim FileList() As String
Dim CurrentFolder As String
Dim openedWorkBook As Workbook, HeadingWorkbook As Workbook
Dim OpenedWorkSheet As Worksheet, HeadingWorkSheet As Worksheet
Dim i, counter, x, j As Integer
Dim LRowHeading, LRowOpenedBook, LColHeading, LColOpenedBook As Long
Dim dict As dictionary
Dim searchValue
'set original workbook with headings to retrieve
Set HeadingWorkbook = ActiveWorkbook
Set HeadingWorkSheet = HeadingWorkbook.Sheets(1)
'find last column on heading worksheet
LColHeading = LastColUsed(HeadingWorkSheet)
'create dictionary to link headers to position in heading worksheet
Set dict = CreateObject("Scripting.Dictionary")
For x = 1 To LColHeading
dict.Add HeadingWorkSheet.Cells(1, x).Value, x
Next x
FileList() = GetFileListArray()
For counter = 1 To UBound(FileList)
Set openedWorkBook = Workbooks.Open(FileList(counter))
Set OpenedWorkSheet = openedWorkBook.Sheets(SHEET_TO_SEARCH)
LColOpenedBook = LastColUsed(openedWorkBook.Sheets(1))
LRowOpenedBook = LastRowUsed(openedWorkBook.Sheets(1))
LRowHeading = LastRowUsed(HeadingWorkSheet)
For j = 2 To LRowOpenedBook Step 1000
LRowHeading = LRowHeading + 1 'move one row down in HeadingWorkbook, each 1000 rows of openedworkbook
For i = 1 To LColOpenedBook 'search headers from a1 to last header
searchValue = OpenedWorkSheet.Cells(1, i).Value 'set search value in to current header
If dict.Exists(searchValue) Then
OpenedWorkSheet.Range(OpenedWorkSheet.Cells(j, i), _
OpenedWorkSheet.Cells(j, i)).Copy _
HeadingWorkSheet.Range(HeadingWorkSheet.Cells(LRowHeading, dict.Item(searchValue)), _
HeadingWorkSheet.Cells(LRowHeading, dict.Item(searchValue)))
End If
Next i
Next j
openedWorkBook.Close (False)
Next ' move on to next file
End Sub
Related
im trying to combine the excel files in the sharepoint folder by using vba, but it seems the path does not working and run time error: 52 keep on coming out due to error in the highlighted code.
Here is the code:
Option Explicit
Sub ConsolidateAllDepartment()
Dim wb As Workbook
Dim wsCopy As Worksheet
Dim myPath As String
Dim myFile As String
Dim myExtension As String
Dim mylCol As Long
Dim Row1 As Long
Dim FileNum As Integer
Dim ActWb As Workbook
'Optimize Macro Speed
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
'Open workbook
Dim nwb As Workbook
Dim nsh As Worksheet
'Open workbook
Set nwb = Workbooks.Add
Set nsh = nwb.Sheets(1)
'Set ActWb = ActiveWorkbook
Set wsCopy = Workbooks("Template for incident closure.xlsm").Sheets("Master Listing (ALL)")
'Copy Table Header
wsCopy.Range("A1:AD1").Copy nsh.Range("A1")
Set nwb = ActiveWorkbook
Dim mylRow As Long
'find last row after clear data
mylRow = Cells(Rows.Count, 1).End(xlUp).Row
'setting input path
myPath = "https:\\workspace.maybank.com.my\sites\Etiqa-Risk\OSRM\ORO\Incident%20Pending%20Closure\by%20Entity-Department\"
'Target File Extension (must include wildcard "*")
myExtension = "*.xlsx"
'Target Path with Ending Extention
myFile = Dir(myPath & myExtension)
'ChDir myPath
'Loop through each Excel file in folder
Do While myFile <> ""
'Set variable equal to opened workbook
Set wb = Workbooks.Open(filename:=myPath & myFile)
'Ensure Workbook has opened before moving on to next line of code
DoEvents
'find last row and last col in wb
wb.Activate
Row1 = Cells(Rows.Count, "A").End(xlUp).Row
'copy the range from A2 to last cell
Range("A2:AD" & Row1).Copy
'paste to main file
nwb.Activate
Range("A" & mylRow + 1).PasteSpecial xlPasteValues
Application.CutCopyMode = False
mylRow = mylRow + Row1 - 1
'Save and Close Workbook
wb.Close SaveChanges:=True
'Ensure Workbook has closed before moving on to next line of code
DoEvents
'Get next file name
myFile = Dir
Loop
ResetSettings:
'Reset Macro Optimization Settings
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Columns("A").Delete
nwb.SaveAs "https://workspace.maybank.com.my/sites/Etiqa-Risk/OSRM/ORM/Incident%20Pending%20Closure/Consolidated%20Files/Consolidated" & Format(Now(), "ddmmyyyy") & ".xlsx"
nwb.Close False
MsgBox "Done"
End Sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'INPUT : Sheet, the worksheet we'll search to find the last row
'OUTPUT : Long, the last occupied row
'SPECIAL CASE: if Sheet is empty, return 1
Public Function LastOccupiedRowNum(Sheet As Worksheet) As Long
Dim lng As Long
If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
With Sheet
lng = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
End With
Else
lng = 1
End If
LastOccupiedRowNum = lng
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'INPUT : Sheet, the worksheet we'll search to find the last column
'OUTPUT : Long, the last occupied column
'SPECIAL CASE: if Sheet is empty, return 1
Public Function LastOccupiedColNum(Sheet As Worksheet) As Long
Dim lng As Long
If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
With Sheet
lng = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
End With
Else
lng = 1
End If
LastOccupiedColNum = lng
End Function
I have a workbook that can export the working sheet to a .csv but it copies it into a new workbook for a second before saving im wondering if there is a way just to copy data from the sheet as is without opening a new workbook ? the code i have is:
Sub CopyToCSV()
Dim FlSv As Variant
Dim MyFile As String
Dim sh As Worksheet
Dim MyFileName As String
Dim DateString As String
Application.ScreenUpdating = False
DateString = Format(Now(), "dd-mm-yyyy_hh-mm-ss-AM/PM") '<~~ uses current time from computer clock down to the second
MyFileName = "Results - " & DateString
Set sh = Sheets("Sheet1")
sh.Copy
FlSv = Application.GetSaveAsFilename(MyFileName, fileFilter:="CSV (Comma delimited) (*.csv), *.csv", Title:="Where should we save this?")
If FlSv = False Then GoTo UserCancel Else GoTo UserOK
UserCancel: '<~~ this code is run if the user cancels out the file save dialog
ActiveWorkbook.Close (False)
MsgBox "Export Canceled"
Exit Sub
UserOK: '<~~ this code is run if user proceeds with saving the file (clicks the OK button)
MyFile = FlSv
With ActiveWorkbook
.SaveAs (MyFile), FileFormat:=xlCSV, CreateBackup:=False
.Close False
End With
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Try this (tested on a simple dataset)
Private Sub ExportToCsv()
Dim ws As Worksheet
Dim delim As String, LastCol As String, csvFile As String, CsvLine As String
Dim aCell As Range, DataRange As Range
Dim ff As Long, lRow As Long, lCol As Long
Dim i As Long, j As Long
'~~> We use "," as delimiter
delim = ","
'~~> Change this to specify your file name and path
csvFile = "C:\Users\Siddharth\Desktop\Sample.Csv"
'~~> Change this to the sheet which you want to export as csv
Set ws = ThisWorkbook.Sheets("Sheet9")
With ws
'~~> Find last row and last column
lRow = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
lCol = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
'~~> Column number to column letter
LastCol = Split(Cells(, lCol).Address, "$")(1)
'~~> This is the range which will be exported
Set DataRange = .Range("A1:" & LastCol & lCol)
'
'~~> Loop through cells in the range and write to text file
'
ff = FreeFile
Open csvFile For Output As #ff
For i = 1 To lRow
For j = 1 To lCol
CsvLine = CsvLine & (delim & Replace(.Cells(i, j).Value, """", """"""""))
Next j
Print #ff, Mid(CsvLine, 2)
CsvLine = ""
Next
'~~> Close text file
Close #ff
End With
End Sub
Sub CopyToCSV()
Dim FlSv As Variant
Dim MyFile As String
Dim sh As Worksheet
Dim MyFileName As String
Dim strTxt As String
Dim vDB, vR() As String, vTxt()
Dim i As Long, n As Long, j As Integer
Dim objStream
Dim strFile As String
Application.ScreenUpdating = False
DateString = Format(Now(), "dd-mm-yyyy_hh-mm-ss-AM/PM") '<~~ uses current time from computer clock down to the second
MyFileName = "Results - " & DateString
FlSv = Application.GetSaveAsFilename(MyFileName, fileFilter:="CSV (Comma delimited) (*.csv), *.csv", Title:="Where should we save this?")
If FlSv = False Then GoTo UserCancel Else GoTo UserOK
UserCancel: '<~~ this code is run if the user cancels out the file save dialog
ActiveWorkbook.Close (False)
MsgBox "Export Canceled"
Exit Sub
UserOK: '<~~ this code is run if user proceeds with saving the file (clicks the OK button)
Set objStream = CreateObject("ADODB.Stream")
MyFile = FlSv
vDB = ActiveSheet.UsedRange
For i = 1 To UBound(vDB, 1)
n = n + 1
ReDim vR(1 To UBound(vDB, 2))
For j = 1 To UBound(vDB, 2)
vR(j) = vDB(i, j)
Next j
ReDim Preserve vTxt(1 To n)
vTxt(n) = Join(vR, ",")
Next i
strtxt = Join(vTxt, vbCrLf)
With objStream
.Charset = "utf-8"
.Open
.WriteText strtxt
.SaveToFile FlSv, 2
.Close
End With
Set objStream = Nothing
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
I am trying to iterate through the rows of a single column in the set range. I set the range as WorkingRange and then set the column I want as SystemCol. how do I loop the each in the set column? I would like to display a message box for each of the rows in the selected column that has a value. The area in the code with the ** is where I am trying to insert the code but what I get is the full column address not a single cell address.
'===============================================================================================
'Description: Loops through the selected site and adds in the vulnerability totals for each _
systems
'Originally written by: Troy Pilewski
'Date: 2016-06-30
'===============================================================================================
'Declares variables
Dim ToWorkbook As Workbook, FromWorkbook As Workbook
Dim ToWorksheet As Worksheet, FromWorkSheet As Worksheet
Dim WorkingRange As Range, WholeRange As Range
Dim FromWorkbookVarient As Variant, ShipNameList() As Variant
Dim TitleString As String, FilterName As String, CurrentSystemName As String, _
ShipNames() As String, SelectedShipName As String
Dim LastRow As Long, ShipRow As Long
Dim StartRow As Integer
Const RowMultiplyer As Integer = 47
'-----------------------------------------------------------------------------------------------
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set ToWorkbook = ActiveWorkbook
Set ToWorksheet = ToWorkbook.ActiveSheet
LastRow = ToWorksheet.Range("Y:Y").Find( _
What:="*", _
After:=ToWorksheet.Range("Y1"), _
LookAt:=xlByRows, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious _
).Row
'MsgBox _
' Prompt:="Y1:Y" & LastRow, _
' Title:="Ship Range"
ShipNameList = ToWorksheet.Range("Y1:Y" & LastRow).Value
For Each Item In ShipNameList
Dim BoundCounter As Integer
If Left(Item, 3) = "USS" Then
BoundCounter = BoundCounter + 1
End If
Next Item
ReDim ShipNames(BoundCounter - 1)
BoundCounter = 0
For Each Item In ShipNameList
If Left(Item, 3) = "USS" Then
ShipNames(BoundCounter) = Item
' Debug.Print ShipNames(BoundCounter)
BoundCounter = BoundCoutner + 1
Else
' Debug.Print UBound(ShipNames())
Exit For
End If
Next Item
TitleString = "Select a ship..."
SelectedShipName = GetChoiceFromChooserForm(ShipNames, TitleString)
If SelectedShipName = "" Then
Exit Sub
End If
ShipRow = ToWorksheet.Range("Y:Y").Find( _
What:=SelectedShipName, _
After:=ToWorksheet.Range("Y1"), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=True _
).Row
'Debug.Print ShipRow
StartRow = 14
If ShipRow > 1 Then
StartRow = (RowMultiplyer * (ShipRow - 1)) + StartRow
Else
StartRow = 14
End If
Set WorkingRange = ToWorksheet.Range("B" & StartRow & ":G" & StartRow + 38)
Set SystemCol = WorkingRange.Columns(2)
'Debug.Print WorkingRange.Address
FilterName = "Excel Files (*.xls), *.xls,Excel Files (*.xlsx), *.xlsx,All Files (*.*), *.*"
TitleString = "Scan File Selection"
**For Each rw In SystemCol
Debug.Print rw.Address
Next rw**
You'd be very well served to add Option Explicit to the top of your code modules to always ensure all variables must be declared.
You never declared SystemCol as a Range, nor rw as Range.
Following that adding .Cells to SystemCol in the loop ensures that you will loop through each individual cell in SystemCol. See below.
For Each rw In SystemCol.Cells
Debug.Print rw.Address
Next rw
I’m relatively new in VBA, and currently I’m working on a macro in Master_file.xlsm, which contains multiple ranges of data that have to fill several .xlsb files in a folder.
Sheet Control contains in A2 the Folder path, which contains all the .xlsb files to be filled, and column D the file names.
Sheet Churn contains at column A the same file names, followed by its respective range to be paste at the .xlsb file.
This is all I have so far.
Sub Fill_NNAs()
Dim FilePath As String
Dim iCell As String
Dim BC As String
Application.EnableCancelKey = xlDisabled
Application.ScreenUpdating = False
ActiveWorkbook.Sheets("Control").Activate
LastRow = Range("D2").End(xlDown).Row
intRowCount = LastRow
FilePath = ActiveSheet.Range("A2").Value
For i = 2 To intRowCount
iCell = Cells(i, 4).Value
BC = Cells(i, 3).Value
Worksheets("Churn").Activate
Columns("A:A").Select
x = Selection.Find(What:=BC, After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
Range(ActiveCell.Offset(1, 1), ActiveCell.Offset(3, 64)).Select
Selection.Copy
Workbooks.Open FileName:=FilePath & iCell, ReadOnly:=False, UpdateLinks:=0
ActiveWorkbook.UpdateLinks = xlUpdateLinksNever
Sheets("Summary_ARD").Select
Range("C89:BN91").Select
ActiveSheet.Paste
ActiveWindow.Close SaveChanges:=True
Workbooks("Master_file.xlsm").Activate
Sheets("Control").Select
Next
MsgBox "Completed successfully!"
End Sub
As you can see, my loop goes to sheet Control, get the first file name, searches for it on Churn, copies its respective range, open Filename.xlsb, activated Summary_ARD sheet, paste it and goes to the next.
It has been working fine, but now I have a new problem:
Some xlsb files have more than one “Summary_ARD” sheet, like Summary_ARD, Summary_ARD (2), Summary_ARD (3), and some have New_ARD sheet instead of Summary_ARD.
So, what my code has to do now when open a new Filename.xlsb is:
Activate the Summary_ARD with the highest number in parenthesis (Summary_ARD (5) instead of (4), etc).
If there is no sheet Summary_ARD (number), activate Summary_ARD.
If there is no sheet Summary_ARD, activate New_ARD.
For all itens above, it has to look only in the visible sheets.
Any ideas?
If whatever your target sheet is is the last sheet in the WB, you can just reference it by its .index number - the last one being sheets.count -
Oh, I restructured your code so you're not using .selection or .activate
Sub Fill_NNAs()
Application.EnableCancelKey = xlDisabled
Application.ScreenUpdating = False
Dim wbDest As Workbook
Dim FilePath As String
FilePath = ActiveSheet.Range("A2").Value
Dim iCell As String
Dim BC As String
Dim rngSearch As Range
Dim lastrow As Integer
lastrow = Range("D2").End(xlDown).Row
Dim wsControl As Worksheet
wsControl = ThisWorkbook.Sheets("Control")
Dim wsChurn As Worksheet
wsChurn -ThisWorkbook.Sheets("Churn")
For i = 2 To lastrow
iCell = wsControl.Cells(i, 4).Value
BC = wsControl.Cells(i, 3).Value
Set rngSearch = wsChurn.Columns(1).Find(What:=BC, After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
Set rngSearch = Range(rngSearch.Offset(1, 1), rngSearch.Offset(3, 64))
Workbooks.Open Filename:=FilePath & iCell, ReadOnly:=False, UpdateLinks:=0
ActiveWorkbook.UpdateLinks = xlUpdateLinksNever
ActiveWorkbook.Sheets(Sheets.Count).Range("C89:BN91") = rngSearch
ActiveWindow.Close SaveChanges:=True
Next
MsgBox "Completed successfully!"
End Sub
Otherwise, you might need to get a little tricky with something like this -
Sub testb()
Dim j As Integer
j = 0
Dim wsDest As Worksheet
For Each ws In ThisWorkbook.Sheets
If InStr(1, ws.Name, "(") Then
If Mid(ws.Name, InStr(1, ws.Name, "(") + 1, 1) > j Then
j = Mid(ws.Name, InStr(1, ws.Name, "(") + 1, 1)
End If
End If
Next
If j = 0 Then
If SheetExists("Summary_ARD") Then
wsDest = ThisWorkbook.Sheets("Summary_ARD")
Else: wsDest = ThisWorkbook.Sheets("New_ARD")
GoTo label
End If
End If
Set wsDest = ActiveWorkbook.Sheets("Summary_ARD(" & j & ")")
label:
'do stuff with wsdest
End Sub
Function SheetExists(strWSName As String) As Boolean
Dim ShTest As Worksheet
On Error Resume Next
Set ShTest = Worksheets(strWSName)
If Not ShTest Is Nothing Then SheetExists = True
End Function
For your loop to find the sheet, this might work
Sub findsheet()
Dim i As Integer
Dim shTest As Worksheet
For i = 1 To 20
On Error GoTo label
Set shTest = Worksheets("Summary_ARD(" & i & ")")
Next
label:
If i > 1 Then
Set shTest = Worksheets("Summary_ARD(" & i - 1 & ")")
GoTo label3
End
On Error GoTo label2
Set shTest = Worksheets("Summary_ARD")
GoTo label3
label2:
Set shTest = Worksheets("New_ARD")
GoTo label3
label3:
'do stuff
End Sub
I don't know if i'm being dumb (probably), but I just put your loop in the place of mine old Sheets("Summary_ARD").Select, and it doesn't work. I got stuck in the "label" line.
Sub Fill_NNAs()
Dim FilePath As String
Dim iCell As String
Dim BC As String
Application.EnableCancelKey = xlDisabled
Application.ScreenUpdating = False
ActiveWorkbook.Sheets("Control").Activate
LastRow = Range("D2").End(xlDown).Row
intRowCount = LastRow
FilePath = ActiveSheet.Range("A2").Value
For i = 2 To intRowCount
iCell = Cells(i, 4).Value
BC = Cells(i, 3).Value
Worksheets("Churn").Activate
Columns("A:A").Select
x = Selection.Find(What:=BC, After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
Range(ActiveCell.Offset(1, 1), ActiveCell.Offset(3, 64)).Select
Selection.Copy Workbooks.Open FileName:=FilePath & iCell, ReadOnly:=False, UpdateLinks:=0 ActiveWorkbook.UpdateLinks = xlUpdateLinksNever
On Error GoTo label
Set shTest = Worksheets("Summary_ARD(" & i & ")")
Next
label:
If i > 2 Then
Set shTest = Worksheets("Summary_ARD(" & i - 1 & ")")
GoTo label3
End
On Error GoTo label2
Set shTest = Worksheets("Summary_ARD")
GoTo label3
label2:
Set shTest = Worksheets("New_ARD")
GoTo label3
label3:
Range("C89:BN91").Select
ActiveSheet.Paste
ActiveWindow.Close SaveChanges:=True
Workbooks("Master_file.xlsm").Activate
Sheets("Control").Select
Next
MsgBox "Completed successfully!"
End Sub
Oh sorry, I don't use your re-writed code.
I have one button macro for reading data from excel files after leaving some(irrelevent starting rows of detail) rows(A1-A10) and merging all those files in single file.
It runs correctly when i use product files(excel files which have details about particular product). But when i use excel files which has company details it reads one row from irrelevant row(A5) then goes to the relevant data part to read.
I am not able to understand why it is reading one row i.e. company name from company excel files. i want it to directly go to (A11)th row to read. Which it does with produt files.
Product files are the files which have particular product details.
Whereas Company Files are the files which has details of all products of particular company.
With my code below, i want to know that why it is reading company name(row A5), which it should not read.
Sub Button2_Click()
Dim basebook As Workbook
Dim mybook As Workbook
Dim sourceRange As Range
Dim destrange As Range
Dim SourceRcount As Long
Dim N As Long
Dim rnum As Long
Dim MyPath As String
Dim SaveDriveDir As String
Dim FName As Variant
SaveDriveDir = CurDir
MyPath = "C:\"
ChDrive MyPath
ChDir MyPath
FName = Application.GetOpenFilename(filefilter:="Excel Files (*.xls), *.xls", _
MultiSelect:=True)
If IsArray(FName) Then
Application.ScreenUpdating = False
Set basebook = ThisWorkbook
For N = LBound(FName) To UBound(FName)
Set mybook = Workbooks.Open(FName(N))
rnum = LastRow(basebook.Worksheets(1)) + 1
Set sourceRange = mybook.Worksheets(1).UsedRange
SourceRcount = sourceRange.Rows.Count
Set destrange = basebook.Worksheets(1).Cells(rnum, "A")
'basebook.Worksheets(1).Cells(rnum, "D").Value = mybook.Name
' This will add the workbook name in column D if you want
sourceRange.Copy destrange
' Instead of this line you can use the code below to copy only the values
' With sourceRange
' Set destrange = basebook.Worksheets(1).Cells(rnum, "A"). _
' Resize(.Rows.Count, .Columns.Count)
' End With
' destrange.Value = sourceRange.Value
mybook.Close False
'Clear Rows
rnum = LastRow(basebook.Worksheets(1)) + 1
While Not rnum = 2
If basebook.Worksheets(1).Cells(rnum, 1).Value = "" Or
Left(basebook.Worksheets(1).Cells
(rnum, 1).Value, 9) = "Copyright" Or Left
(basebook.Worksheets(1).Cells(rnum, 1).Value, 4) = "Free" Or Left
(basebook.Worksheets(1).Cells(rnum, 1).Value, 7) = "Product" Or
Left(basebook.Worksheets(1).Cells(rnum, 1).Value, 9) = "Intl Port" Or
Left(basebook.Worksheets(1).Cells(rnum, 1).Value, 5) = "House" Or
Left(basebook.Worksheets(1).Cells(rnum, 1).Value, 7) = "Arrival" Or
Left(basebook.Worksheets(1).Cells(rnum, 1).Value, 5) = "Bill " Then
basebook.Worksheets(1).Rows(rnum).Delete
End If
rnum = rnum - 1
Wend
Next
End If
ChDrive SaveDriveDir
ChDir SaveDriveDir
Application.ScreenUpdating = True
End Sub
Function LastRow(sh As Worksheet)
On Error Resume Next
LastRow = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
Instead of this:
Set sourceRange = mybook.Worksheets(1).UsedRange
SourceRcount = sourceRange.Rows.Count
Try this:
With mybook.Worksheets(1)
SourceRcount = .UsedRange.Rows.Count
Set sourceRange = .UsedRange.Offset(10, 0).Resize(RowSize:=SourceRcount - 10)
End With
By directly copying only what you want you avoid the need to delete the rows later.