Iterate through spreadsheets in a folder and collect a value from each - excel

I'm trying to write code that on Commandbutton2_Click searches through the folder that the file is in, takes a value from the same cell in each file and adds these together.
I have this:
Private Sub CommandButton2_Click()
Dim lCount As Long
Dim wbResults As Workbook
Dim wbCodeBook As Workbook
Dim strFolderPath As String
Dim strToolNumber As String
Dim RingCount As Integer
RingCount = 0
strToolNumber = CStr(Sheets("Sheet1").Range("B9").Value)
strFolderPath = "T:\Engineering\Tooling\Tooling Control Engineering\Press Tool Inspection Records\" & strToolNumber & "\"
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.EnableEvents = False
On Error Resume Next
Set wbCodeBook = ThisWorkbook
With Application.FileSearch
.NewSearch
'Change path to suit
.LookIn = strFolderPath
.FileType = msoFileTypeExcelWorkbooks
If .Execute > 0 Then 'Workbooks in folder
For lCount = 1 To .FoundFiles.Count 'Loop through all
'Open Workbook x and Set a Workbook variable to it
Set wbResults = Workbooks.Open(FileName:=.FoundFiles(lCount), UpdateLinks:=0)
'DO YOUR CODE HERE
RingCount = Val(RingCount) + ActiveWorkbook.Sheets("Sheet1").Range("F11").Value
wbResults.Close SaveChanges:=False
Next lCount
End If
End With
On Error GoTo 0
ActiveSheet.Unprotect Password:=""
ActiveWorkbook.Sheets("Sheet1").Range("F13").Value = (RingCount + ActiveWorkbook.Sheets("Sheet1").Range("F11").Value)
ActiveSheet.Protect Password:=""
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.EnableEvents = True
End Sub
whose main body was pieced together from different google searches - but it continually returns a value of 0 (despite the cells in the other sheets having values).
I read somewhere that Application.Filesearch does not work for versions of Excel later than 2003, could this be the source of the problem?

Its possible to pull that value youre interested in without opening each workbook. Its much more efficient and reliable.
This code iterates through all files in the path variable and pulls values without opening the Excel files. It then prints the values starting at F20. You can then make another wrapper function to sum them up and delete or whatever you want. Hope this helps
Private Sub CommandButton2_Click()
Dim tool As String
tool = CStr(Sheets("Sheet1").range("B9").Value)
Dim path As String
path = "T:\Engineering\Tooling\Tooling Control Engineering\Press Tool Inspection Records\" & strToolNumber & "\"
Dim fname
fname = Dir(CStr(path)) ' gets the filename of each file in each folder
Do While fname <> ""
If fname <> ThisWorkbook.Name Then
PullValue path, fname ' add values
End If
fname = Dir ' get next filename
Loop
End Sub
Private Sub PullValue(path As String, ByVal fname As String)
With range("F" & (range("F" & Rows.Count).End(xlUp).Row + 1))
.Formula = "='" & path & "[" & fname & "]Sheet1'!F11"
.Value = .Value
End With
End Sub

Related

Copy rows of multiple workbooks into one main workbook

I want to open a workbook that contains only one sheet,
copy data up to column AC until last available row in column A,
paste the data into first empty row in column A in workbook "Mergedsheet.xlsx".
I want to loop over all workbooks present in a specific folder, but get lots of errors.
Sub MergeNew()
Dim WorkBk As Workbook
Dim MergedSheet As Worksheet
Dim SourceData As Range
Dim DestinationData As Range
Dim lastRow As Long
Dim NextRow As Range
Dim FolderPath As String
Dim FileNames As String
Application.ScreenUpdating = False
Application.DisplayAlerts = False
FolderPath = "E:\Jan to March 2019\Bharuch 31\"
FileNames = Dir(FolderPath & "*.xls*")
Do While FileNames <> ""
Set WorkBk = Workbooks.Open(FolderPath & FileNames)
Range("A1:AC1").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Workbooks.Open Filename:="E:\Jan to March 2019\Bharuch 31\MergedSheet.xlsx"
lastRow = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row + 1
Range("A" & lastRow).Select
ActiveSheet.Paste
'ActiveWindow.Close SaveChanges:=True
'ActiveWindow.Close SaveChanges:=False
Application.CutCopyMode = False
FileNames = Dir()
Loop
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
You are looping through a folder and copy-pasting each workbook's first sheet's data to workbook A. However, workbook A is also in that folder. So you should take care to skip it (when looping).
(Alternatively, you could provide a different argument to the DIR function (e.g. some wildcard criteria that excludes workbook A if possible), so that you don't have to constantly check inside the loop.)
Untested.
Option Explicit
Private Sub MergeNew()
'Application.ScreenUpdating = False 'Uncomment this when you know code is working.
'Application.DisplayAlerts = False 'Uncomment this when you know code is working.
Dim folderPath As String
folderPath = GetFolderPath(titleToShow:="Select the folder containing the files to loop through.")
Dim Filename As String
Filename = Dir$(folderPath & "*.xls*")
If Len(Filename) = 0 Then
MsgBox "Could not find a relevant file in '" & folderPath & "'. Code will stop running now."
Exit Sub ' No point in carrying on in such a case.
End If
Dim destinationFolderPath As String
destinationFolderPath = GetFolderPath(titleToShow:="Select the folder to save the 'MergedSheet.xlsx' file to.")
Dim destinationWorkbook As Workbook
Set destinationWorkbook = Application.Workbooks.Add
' This line may throw an error
destinationWorkbook.SaveAs Filename:=destinationFolderPath & "MergedSheet.xlsx", FileFormat:=xlOpenXMLWorkbook
Dim destinationSheet As Worksheet
Set destinationSheet = destinationWorkbook.Worksheets(1) ' I assume there's only 1 sheet in there, but change as necessary.
Do Until Len(Filename) = 0
Dim fullFilePathToOpen As String
fullFilePathToOpen = folderPath & Filename
If fullFilePathToOpen <> destinationWorkbook.FullName Then ' Probably could have just compared filename since directory is the same, but this is more explicit
Dim sourceWorkbook As Workbook
Set sourceWorkbook = Application.Workbooks.Open(Filename:=fullFilePathToOpen, ReadOnly:=True) ' If you don't make changes to the workbook you open, better to open as read-only
Dim sourceSheet As Worksheet
Set sourceSheet = sourceWorkbook.Worksheets(1) ' You say there's only one worksheet in there, so referring by index should be okay (for now)
Dim lastSourceRow As Long
lastSourceRow = sourceSheet.Cells(sourceSheet.Rows.Count, "A").End(xlUp).Row ' Assume last row can be determined from column A alone
Dim lastDestinationRow As Long
lastDestinationRow = destinationSheet.Cells(destinationSheet.Rows.Count, "A").End(xlUp).Row + 1
If destinationSheet.Rows.Count < (lastDestinationRow + lastSourceRow) Then
MsgBox "Ran out of rows (in sheet '" & sourceSheet.Name & "' of workbook '" & destinationWorkbook.Name & "')"
Exit Sub
End If
sourceSheet.Range("A1", sourceSheet.Cells(lastSourceRow, "AC")).Copy Destination:=destinationSheet.Cells(lastDestinationRow, "A")
sourceWorkbook.Close False
End If
Filename = Dir$()
Loop
'Application.ScreenUpdating = True 'Uncomment this when you know code is working.
'Application.DisplayAlerts = True 'Uncomment this when you know code is working.
End Sub
Private Function GetFolderPath(Optional ByVal titleToShow As String = vbNullString) As String
With Application.FileDialog(msoFileDialogFolderPicker)
If Len(titleToShow) > 0 Then .Title = titleToShow
.AllowMultiSelect = False ' Only one is allowed.
.Show
If .SelectedItems.Count = 0 Then
MsgBox "Folder selection appears to have cancelled. Code will stop running now"
End
End If
GetFolderPath = .SelectedItems(1) & "\"
End With
End Function

VBA - Loop through files in a folder ONLY if file not already included in a list

I am currently using a piece of code to loop through all files in a folder and copy certain cells from each file into a master list. Currently there are a number of files being added into the folder every week. The code is then re-ran and all files are looped through again. One of the columns in the master list includes the filenames of previously looped files.
I would like to modify this code to ONLY loop through files that have not previously been looped through (i.e files with filenames that are not already included in the list created by previously running the code) and add data into the already existing list. Here is the code that I am currently using:
Sub CopyFromFolderExample()
' updated 2018-11-13 by OPE
' copies values from the first worksheet from all workbooks in a given folder
Dim strFolder As String, strFile As String, r As Long, wb As Workbook
Dim varTemp(1 To 6) As Variant ' variable to hold the values you want to copy
Application.ScreenUpdating = False
strFolder = "D:\Other\Barbara's Bakery Ltd\Inv\" ' include last path separator
' prepare the target worksheet
With ThisWorkbook.Worksheets(1)
.Range("A4:E" & .Rows.Count).ClearContents ' clear any existing content below the header row
r = .Range("A" & .Rows.Count).End(xlUp).Row ' last non-empty row in column A
End With
strFile = Dir(strFolder & "*.xl*") ' the first workbook found in the folder
Do While Len(strFile) > 0 ' repeat for each *.xl* file in the folder
Application.StatusBar = "Reading data from " & strFile & "..."
Set wb = Workbooks.Add(strFolder & strFile) 'open a copy of the workbook, just in case it is already open
With wb.Worksheets(1) ' specify source worksheet
' read input values
varTemp(1) = .Range("A13").Value
varTemp(2) = .Range("H8").Value
varTemp(3) = .Range("H9").Value
varTemp(4) = .Range("H36").Value
varTemp(5) = .Range("H37").Value
varTemp(6) = strFile
End With
wb.Close False ' close the workbook copy, not necessary to save any changes
' write the values from the source workbook to the target worksheet
With ThisWorkbook.Worksheets(1)
r = r + 1
.Range("A" & r & ":F" & r).Formula = varTemp
End With
strFile = Dir ' next source workbook
Loop
Application.StatusBar = False
Application.ScreenUpdating = True
End Sub
Given that you appear to be storing your previously looped book names in Column F, you can just look for your current books name there. If the book name is there, we will skip the file. If the book name is not there, we will proceed with your code.
You can use a function Looped to check for your value which will return either
TRUE: The book has already been looped
FALSE: The book has not been looped
You then need to build your action statements around the result of this function. If Not Looped(strFile, ws) Then which translates to If Looped = FALSE Then proceed.
I also declared a worksheet variable ws to get rid of two of your with blocks and to be able to pass this variable into the below function.
Option Explicit
Sub CopyFromFolderExample()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets(1)
Dim strFolder As String, strFile As String, r As Long, wb As Workbook
Dim varTemp(1 To 6) As Variant
Application.ScreenUpdating = False
strFolder = "D:\Other\Barbara's Bakery Ltd\Inv\"
ws.Range("A4:E" & ws.Rows.Count).ClearContents
r = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
strFile = Dir(strFolder & "*.xl*")
Do While Len(strFile) > 0
If Not Looped(strFile, ws) Then
Application.StatusBar = "Reading data from " & strFile & "..."
Set wb = Workbooks.Add(strFolder & strFile)
With wb.Worksheets(1)
varTemp(1) = .Range("A13").Value
varTemp(2) = .Range("H8").Value
varTemp(3) = .Range("H9").Value
varTemp(4) = .Range("H36").Value
varTemp(5) = .Range("H37").Value
varTemp(6) = strFile
End With
wb.Close False
r = r + 1
ws.Range(ws.Cells(r, 1), ws.Cells(r, 6)).Formula = varTemp
End If
strFile = Dir
Loop
Application.StatusBar = False
Application.ScreenUpdating = True
End Sub
Private Function Looped(strFile As String, ws As Worksheet) As Boolean
Dim Found As Range
Set Found = ws.Range("F:F").Find(strFile)
If Found Is Nothing Then
Looped = False
Else
Looped = True
End If
End Function

Combine multiple files to one sheet as values and remove filters

I would like to combine sheets with the same name & format from multiple files into a single summary sheet. I used this code to do it but I found it won't copy any filtered data or link cells. I also tried a couple codes to remove the filter, and the copied data becomes uncontinuous. Could someone look into this and help me? Thanks!
Sub Multiple_to_One()
Dim MyPath, MyName, AWbName
Dim Wb As Workbook, WbN As String
Dim G As Long
Dim Num As Long
Dim BOX As String
Dim lo As ListObject
Application.ScreenUpdating = False
MyPath = ActiveWorkbook.Path
MyName = Dir(MyPath & "\" & "*.xlsm")
AWbName = ActiveWorkbook.Name
Do While MyName <> ""
If MyName <> AWbName Then
Set Wb = Workbooks.Open(MyPath & "\" & MyName)
With Workbooks(1).ActiveSheet
Wb.Sheets(13).UsedRange.Copy .Cells(.Range("B65536").End(xlUp).Row + 1, 1)
Wb.Close False
End With
End If
MyName = Dir
Loop
MsgBox "All done.", vbInformation, "bingo"
End Sub
This is a bit of a brute force method, but seems to work:
Sub Summarize()
Dim sourcePath As String
Dim sourceName As String
Dim sourceWorkbook as Workbook ' Workbook to be copied
Dim sourceSheet as Worksheet
Dim thisWorkbookName as String
Dim copyCell as Range
Dim sourceBase as Range ' Summary starts here
Application.ScreenUpdating = False
sourcePath = ActiveWorkbook.Path
thisWorkbookName = ActiveWorkbook.Name
sourceName = Dir(MyPath & "\" & "*.xlsm")
Set sourceBase = Workbooks(1).ActiveSheet.Range("A1") ' Set to what you want
Do While sourceName <> ""
If sourceName <> thisWorkbookName Then
Set sourceWorkbook = Workbooks.Open(sourcePath & "\" & sourceName)
Set sourceSheet = sourceWorkbook.Sheets(13)
For Each copyCell In sourceSheet.UsedRange
copyCell.Copy sourceBase.Offset(copyCell.Row - 1, copyCell.Column - 1)
Next
Set sourceBase = sourceBase.Offset(sourceSheet.UsedRange.Rows.Count)
Set copyCell = Nothing
Set sourceSheet = Nothing
sourceWorkbook.Close False
End If
sourceName = Dir
Loop
Application.ScreenUpdating = True
MsgBox "All done.", vbInformation, "bingo"
End Sub
I'm just manually copying every cell in the used range into the target sheet. The base cell gets reset after each sheet, so it should just keep appending to the target sheet.
Caveat
I've only tested the inner code in my own sheet. I made adjustments on the fly to fit everything into your original logic. The entire function above should replace your original function. If you have errors, it's because I mistyped something. My apologies.
I set the autofiltermode to False. This worked in my case.
Wb.Sheets(13).AutoFilterMode = False
Here is the modified code.
Sub Multiple_to_One()
Dim MyPath, MyName, AWbName
Dim Wb As Workbook, WbN As String
Dim G As Long
Dim Num As Long
Dim BOX As String
Dim lo As ListObject
Application.ScreenUpdating = False
MyPath = ActiveWorkbook.Path
MyName = Dir(MyPath & "\" & "*.xlsm")
AWbName = ActiveWorkbook.Name
Do While MyName <> ""
If MyName <> AWbName Then
Set Wb = Workbooks.Open(MyPath & "\" & MyName)
Wb.Sheets(13).AutoFilterMode = False
ThisWorkbook.Activate
With Workbooks(1).ActiveSheet
Wb.Sheets(13).UsedRange.Copy .Cells(.Range("B65536").End(xlUp).Row + 1, 1)
Wb.Close False
End With
End If
MyName = Dir
Loop
Application.ScreenUpdating = True
MsgBox "All done.", vbInformation, "bingo"
End Sub

Copying collections of sheets identified by name list to new workbooks

I am trying to copy specific collections sheets within an excel workbook in separate workbooks. Not being a vba coder I have used and adapted code found here and other resource sites. I believe I am now very close having grasped the basic concepts but cannot figure out what i am doing wrong, triggering the below code causes the first new workbook to be created and the first sheet inserted but breaks at that point.
My code is below, additional relevant info - there is a sheet called 'List' which has a column of names. Each name on the list has 2 sheets which I am trying to copy 2 by 2 into new sheet of the same name. the sheets are labelled as the name and the name + H (e.g Bobdata & BobdataH)
Sub SheetCreate()
'
'Creates an individual workbook for each worksname in the list of names.
'
Dim wbDest As Workbook
Dim wbSource As Workbook
Dim sht As Object
Dim strSavePath As String
Dim sname As String
Dim relativePath As String
Dim ListOfNames As Range, LRow As Long, Cell As Range
With ThisWorkbook
Set ListSh = .Sheets("List")
End With
LRow = ListSh.Cells(Rows.Count, "A").End(xlUp).Row '--Get last row of list.
Set ListOfNames = ListSh.Range("A1:A" & LRow) '--Qualify list.
With Application
.ScreenUpdating = False '--Turn off flicker.
.Calculation = xlCalculationManual '--Turn off calculations.
End With
Set wbSource = ActiveWorkbook
For Each Cell In ListOfNames
sname = Cell.Value & ".xls"
relativePath = wbSource.Path & "\" & sname
Sheets(Cell.Value).Copy
Set wbDest = ActiveWorkbook
Application.DisplayAlerts = False
ActiveWorkbook.CheckCompatibility = False
ActiveWorkbook.SaveAs Filename:=relativePath, FileFormat:=xlExcel8
Application.DisplayAlerts = True
wbSource.Activate
Sheets(Cell.Value & "H").Copy after:=Workbooks(relativePath).Sheets(Cell.Value)
wbDest.Save
wbDest.Close False
Next Cell
MsgBox "Done!"
End Sub
You can try to change
Sheets(Cell.Value & "H").Copy after:=Workbooks(relativePath).Sheets(Cell.Value)
to
Sheets(Cell.Value & "H").Copy after:=wbDest.Sheets(Cell.Value)
Also it would be good idea to check if file already exists in selected location. For this you can use function:
Private Function findFile(ByVal sFindPath As String, Optional sFileType = ".xlsx") As Boolean
Dim obj_fso As Object: Set obj_fso = CreateObject("Scripting.FileSystemObject")
findFile = False
findFile = obj_fso.FileExists(sFindPath & "/" & sFileType)
Set obj_fso = Nothing
End Function
and change sFileType = ".xlsx" to "*" or other excet file type.
This was the code i created to create a new workbook and then copy sheet contents from existing one to the new one. Hope it helps.
Private Sub CommandButton3_Click()
On Error Resume Next
Application.ScreenUpdating = False
Application.DisplayAlerts = False
TryAgain:
Flname = InputBox("Enter File Name :", "Creating New File...")
MsgBox Len(Flname)
If Flname <> "" Then
Set NewWkbk = Workbooks.Add
ThisWorkbook.Sheets(1).Range("A1:J100").Copy
NewWkbk.Sheets(1).Range("A1:J100").PasteSpecial
Range("A1:J100").Select
Selection.Columns.AutoFit
AddData
Dim FirstRow As Long
Sheets("Sheet1").Range("A1").Value = "Data Recorded At-" & Format(Now(), "dd-mmmm-yy-h:mm:ss")
NewWkbk.SaveAs ThisWorkbook.Path & "\" & Flname
If Err.Number = 1004 Then
NewWkbk.Close
MsgBox "File Name Not Valid" & vbCrLf & vbCrLf & "Try Again."
GoTo TryAgain
End If
MsgBox "Export Complete Close the Application."
NewWkbk.Close
End If
End Sub

Import sheets change sheet name

Im importing alot of sheetnames from different files using this VBA:
Sub ImportSheets()
Dim sPath As String
Dim sFname As String
Dim wBk As Workbook
Dim wSht As Variant
Application.EnableEvents = False
Application.ScreenUpdating = False
sPath = InputBox("Enter a full path to workbooks")
ChDir sPath
sFname = InputBox("Enter a filename pattern")
sFname = Dir(sPath & "\" & sFname & ".xl*", vbNormal)
wSht = InputBox("Enter a worksheet name to copy")
Do Until sFname = ""
Set wBk = Workbooks.Open(sFname)
Windows(sFname).Activate
Sheets(wSht).Copy After:=ThisWorkbook.Sheets(1)
ActiveSheet.Name = ActiveSheet.Range("A9")
wBk.Close False
sFname = Dir()
Loop
ActiveWorkbook.Save
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Right now the net sheetname is whatever value that is written in A9, is there a way i can change that, so the sheet will be renamed to the filename it is imported from?
Alternative solution could be to rename it "Import" & Suffix, however im not sure how to add the suffix 1-1000 ect.
You have the workbook name as sFname. Peel off the extension and use that.
ActiveSheet.Name = left(sFname, instrrev(sFname, chr(46))-1)
In order to have the same name as the Excel file, then simply try this:
ActiveSheet.Name = wBk.Name
If you want to have the same name as the worksheet, from which you are copying,
instead of ActiveSheet.Name = ActiveSheet.Range("A9"), this is the code you need:
ActiveSheet.Name = Worksheets(wSht).Name
It will take exactly the correct name. Or even ActiveSheet.Name = wSht, as far as you are specifying it exactly through the InputBox.
In general, before trying to copy the corresponding worksheet, you may check whether it exists and only do the copy if it is there. This is one way (see the link below for others) to do it:
If WorksheetExists(wSht) Then
Sheets(wSht).Copy After:=ThisWorkbook.Sheets(1)
ActiveSheet.Name = ActiveSheet.Range("A9")
End If
Function WorksheetExists(sName As String) As Boolean
WorksheetExists = Not WorksheetFunction.IsErr(Evaluate("'" & sName & "'!A1"))
End Function
In order to get Import + counter, try something like this in your code:
Option Explicit
Public Sub TestMe()
Dim importName As String
Dim cnt
Do Until cnt = 10
cnt = cnt + 1
importName = "Import" & cnt
Debug.Print importName
Loop
End Sub
Simply make sure that you always increment +1 the worksheet's name.
Test or check if sheet exists

Resources