I'm fairly new to using VBA, but I currently have a code written that does the following:
Searches within a folder, all excel files which contain a specific worksheet, and outputs in to a master sheet.
I am trying to add a column, either at the beginning or end of the master sheet which indicates the file source name. My code is the following
Sub CombineWorkbooks()
'Declare the variables
Dim arrFiles() As String
Dim strPath As String
Dim strFile As String
Dim wkbDest As Workbook
Dim wksDest As Worksheet
Dim wkbSource As Workbook
Dim wksSource As Worksheet
Dim SourceRange As Range
Dim SourceRowCount As Long
Dim NextRow As Long
Dim LastRow As Long
Dim LastCol As Long
Dim FileCnt As Long
Dim Cnt As Long
Dim i As Long
Dim CalcMode As Long
'Specify the path to the folder containing the files
strPath = "FOLDER PATH\"
'Make sure that the path ends in a backslash
If Right(strPath, 1) <> "\" Then strPath = strPath & "\"
'Check if the path exists
If Len(Dir(strPath, vbDirectory)) = 0 Then
MsgBox "The path to your folder does not exist. Please check" & vbCrLf & _
"the path, and try again!", vbExclamation
Exit Sub
End If
'Get the first Excel file from the folder
strFile = Dir(strPath & "*.xls", vbNormal)
'Fill the array with a list of Excel files in the folder...
FileCnt = 0
Do While Len(strFile) > 0
'...except this workbook, in case it's in the same folder
If strFile <> ThisWorkbook.Name Then
FileCnt = FileCnt + 1
ReDim Preserve arrFiles(1 To FileCnt)
arrFiles(FileCnt) = strFile
End If
'Get the next Excel file from the folder
strFile = Dir
Loop
'If no Excel files were found, exit the sub
If FileCnt = 0 Then
MsgBox "No Excel files were found...", vbExclamation
Exit Sub
End If
'Change the settings for Calculation, DisplayAlerts, EnableEvents,
'and ScreenUpdating
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.DisplayAlerts = False
.EnableEvents = False
.ScreenUpdating = False
End With
'Create a new workbook with one worksheet
Set wkbDest = Workbooks.Add(xlWBATWorksheet)
'Set the destination worksheet
Set wksDest = wkbDest.Worksheets(1)
'Specify the row in which to start copying the data
NextRow = 1
'Loop through each Excel file in the array...
Cnt = 0
For i = LBound(arrFiles) To UBound(arrFiles)
'Open the current file
Set wkbSource = Workbooks.Open(strPath & arrFiles(i))
'Set the source worksheet
On Error Resume Next
Set wksSource = wkbSource.Worksheets("Worksheet you are looking to import")
On Error GoTo 0
'Check if the worksheet exists
If Not wksSource Is Nothing Then
With wksSource
'Find the last used row in Column A
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
'Find the last used column in Row 1
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
'Check if the worksheet contains data beyond column headers
If LastRow > 1 Then
'Increase the count by one
Cnt = Cnt + 1
'Set the source range...
If Cnt = 1 Then
'...including the column headers
Set SourceRange = .Range("A1", .Cells(LastRow, LastCol))
Else
'...excluding the column headers
Set SourceRange = .Range("A2", .Cells(LastRow, LastCol))
End If
'Count the number of rows in the source range
SourceRowCount = SourceRange.Rows.Count
'If there aren't enough rows in the destination sheet,
'exit the sub
If NextRow + SourceRowCount - 1 > wksDest.Rows.Count Then
MsgBox "Sorry, there are not enough rows available " & _
"in the destination worksheet!", vbExclamation
wkbSource.Close savechanges:=False
GoTo ExitSub
End If
'Copy the data from the source range to the destination sheet
SourceRange.Copy
With wksDest.Cells(NextRow, "A")
.PasteSpecial Paste:=xlPasteValues
.PasteSpecial Paste:=xlPasteFormats
End With
'Determine the next available row
NextRow = NextRow + SourceRowCount
End If
End With
'Set the object variable for the source worksheet to Nothing
Set wksSource = Nothing
End If
'Close the current file, without saving it
wkbSource.Close savechanges:=False
Next i
'Check if any data has been copied to the destination worksheet
If Cnt > 0 Then
'Select the first cell and change the width of the columns to
'achieve the best fit
With wksDest
.Cells(1).Select
.Columns.AutoFit
End With
Else
'Display message box advising user that no data was available to be copied
MsgBox "No data was available to be copied...", vbInformation
'Close the destination workbook, without saving it
wkbDest.Close savechanges:=False
End If
ExitSub:
'Restore the settings for Calculation, DisplayAlerts, EnableEvents,
'and ScreenUpdating
With Application
.Calculation = CalcMode
.DisplayAlerts = True
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
Any help would be greatly appreciated!
You might want to look at Power Query's "Import from folder" option. When you import all the files from a folder. Using PQ, you can import all the files from a folder (which appends the file name as a new column in the process) and combine and edit that information. One procedure you can do in Power Query is to navigate to a specific worksheet by its name. If you tried to do this navigation on a workbook that didn't have this name, it would cause an error to be raised. In PQ, you can also tell the query to remove any errors. Combined, you could gather all the files in various folders, using a file that has your specific worksheet, you can create a sample query to drill into that worksheet, and perform your other transformations. If you do this step, then remove all the errors, you should be left only with the files that have the worksheet you are looking for, and have the file name for each of those files alongside your data, and that can be dumped into a master table on your worksheet. Plus, you don't have to deal with any overly complicated VBA code (though, I do so love VBA).
Hope this helps!
Related
I am attempting to extra data from multiple .xlsm in a folder from a specific cell. The idea is to take a folder that has multiple .xlsm files and extract a specific cell into my current workbook.
See code.
Option Explicit
Const FOLDER_PATH = "C:\Users\maxd\OneDrive - Nortek, Inc\Coil Test Data\coils_35_and_36\36\WET\Testing\" 'REMEMBER END BACKSLASH
Sub ImportWorksheets()
'=============================================
'Process all Excel files in specified folder
'=============================================
Dim sFile As String 'file to process
Dim wsTarget As Worksheet
Dim wbSource As Workbook
Dim wsSource As Worksheet
Dim rowTarget As Long 'output row
rowTarget = 7
'check the folder exists
If Not FileFolderExists(FOLDER_PATH) Then
MsgBox "Specified folder does not exist, exiting!"
Exit Sub
End If
'reset application settings in event of error
'On Error GoTo errHandler
'Application.ScreenUpdating = False
'set up the target worksheet
Set wsTarget = Sheets("Sheet1")
'loop through the Excel files in the folder
sFile = Dir(FOLDER_PATH & "*.xlsm*")
Do Until sFile = ""
'open the source file and set the source worksheet - ASSUMED WORKSHEET(1)
Set wbSource = Workbooks.Open(FOLDER_PATH & sFile)
Set wsSource = wbSource.Worksheets("Summary")
'import the data
With wsTarget
.Range("I" & rowTarget).Value = wsSource.Range("B25").Value
'optional source filename in the last column
.Range("N" & rowTarget).Value = sFile
End With
'close the source workbook, increment the output row and get the next file
wbSource.Close SaveChanges:=False
rowTarget = rowTarget + 1
sFile = Dir()
Loop
errHandler:
On Error Resume Next
Application.ScreenUpdating = True
'tidy up
Set wsSource = Nothing
Set wbSource = Nothing
Set wsTarget = Nothing
End Sub
Private Function FileFolderExists(strPath As String) As Boolean
If Not Dir(strPath, vbDirectory) = vbNullString Then FileFolderExists = True
End Function
Actual Results = it does nothing as if there is not a file in the folder.
Expected Results = It will pull the data from cell B25 and insert it to I7 of my current worksheet.
EDIT: When I F8 through the code, it gets to "Set wsSource = wbSource.Worksheets("Summary")" Then I get a runtime error 91
I was really hoping I could figure this out but haven't had any luck. The following VBA allows users to import data from a separate file and determine unique variables to be analyzed, initiated by a single command button. The issue occurs as the final sub is called (filtering for unique variables). I have set .ScreenUpdating = false and set variables back to null after use. As for the sheets in the workbook, they currently do not contain data or formulas but will need to in order to analyze the data further.
Any help in identifying heavy memory usage would be appreciated.
64 bit is unfortunately not an option either
Located in Module1:
Global PathAndFile As String
Global FileName As String
Sub SelectFile()
Application.ScreenUpdating = False
Dim fd As FileDialog
Dim InDir As String
Dim wb As Workbook
InDir = CurDir() 'Save current directory
Set fd = Application.FileDialog(msoFileDialogFilePicker)
With fd
.InitialFileName = CurDir & "\" 'Startup folder
.AllowMultiSelect = False
.Filters.Clear
.Filters.Add "All Excel Files", "*.csv" 'Display csv files only
If .Show = False Then
MsgBox "User canceled without selecting."
ChDir (InDir) 'Change back to Initial directory if user cancels
Exit Sub
End If
'contains the path and filename of selected file
PathAndFile = .SelectedItems(1)
End With
'contains the filename (without the path)
FileName = Right(PathAndFile, Len(PathAndFile) - _
InStrRev(PathAndFile, "\"))
'Clear storage sheet
ThisWorkbook.Worksheets("DataTransferred").Cells.Clear
Call rData
End Sub
Sub rData()
'Retrieve Data
Dim lRow As Long
Dim lCol As Long
Dim Datawb As Workbook
'Open Selected workbook
Set Datawb = Workbooks.Open(PathAndFile)
With Datawb
'Find the last non-blank cell in column A(1)
lRow = Cells(Rows.Count, 1).End(xlUp).Row
'Find the last non-blank cell in row 1
lCol = Cells(1, Columns.Count).End(xlToLeft).Column
'Copy data and paste in new this workbook
Range(Cells(1, 1), Cells(lRow, lCol)).Copy _
Destination:=ThisWorkbook.Worksheets("DataTransferred").Cells(1, 1)
End With
Workbooks(FileName).Close
'Clear Memory
lRow = 0
lCol = 0
strPathAndFile = vbNullString
strFileName = vbNullString
'Sort data
Call Worksheets("DataTransferred").VariableSelect '<<<Run-Time Error 7
Application.ScreenUpdating = True
End Sub
Located in Sheets("DataTransffered"):
Sub VariableSelect()
'Determine unique variables out of assortment
Dim rngDest As Range
If ThisWorkbook.Worksheets("DataTransferred").Cells = Empty Then Exit Sub
'Determine destination for varilables
Set rngDest = ThisWorkbook.Sheets("Analysis").Range("A1")
rngDest.ClearContents
'Select cells with in column (B) and apply filter
Me.Range(Me.Range("B1"), Me.Cells(Rows.Count, 2).End(xlUp)).AdvancedFilter _
Action:=xlFilterCopy, CopyToRange:=rngDest, Unique:=True
End Sub
Copying worksheets from multiple workbooks into current workbook
Hi I was wondering if anybody if you guys could help me out?
Im trying to copy multiple workbooks and just save it into only one worksheet.
I have 2000 diffrent workbooks with the diffrent amount of rows, The ammount of cells is the same and it dosent change and they are all at the first sheet in every workbook.
Im new with this kind of stuff so i'm thankfull for all help u can offer, I cant make it work. I'm using excel 2010
This is what I got atm:
Sub LoopThroughDirectory()
Dim MyFile As String
Dim erow
Dim Filepath As String
Filepath = “C:\test\”
MyFile = Dir("test\")
Do While Len(MyFile) > 0
If MyFile = "master.xlsm" Then
Exit Sub
End If
Range(Range("a1"), ActiveCell.SpecialCells(xlLastCell)).Select
Selection.Name = "PivotData"
Workbooks.Open (Filepath & MyFile)
Range("A2:AD20").Copy
ActiveWorkbook.Close
erow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
ActiveSheet.Paste Destination:=Worksheets("sheet1").Range(Cells(erow, 1), Cells(erow, 1))
MyFile = Dir
Loop End
Sub
I've re-written your code by applying what I posted in the comment.
Try this out: (I stick with your logic using the DIR function)
Sub test()
Dim MyFile As String, MyFiles As String, FilePath As String
Dim erow As Long
'~~> Put additional variable declaration
Dim wbMaster As Workbook, wbTemp As Workbook
Dim wsMaster As Worksheet, wsTemp As Worksheet
FilePath = "C:\test\"
MyFiles = "C:\test\*.xlsx"
MyFile = Dir(MyFiles)
With Application
.ScreenUpdating = False
.DisplayAlerts = False
End With
'~~> Set your declared variables
Set wbMaster = ThisWorkbook 'if you want to consolidate files in this workbook
Set wsMaster = wbMaster.Sheets("Sheet1") 'replace Sheet1 to suit
Do While Len(MyFile) > 0
'Debug.Print MyFile
If MyFile <> "master.xlsm" Then
'~~> Open the file and at the same time, set your variable
Set wbTemp = Workbooks.Open(Filename:=FilePath & MyFile, ReadOnly:=True)
Set wsTemp = wbTemp.Sheets(1) 'I used index, you said there is only 1 sheet
'~~> Now directly work on your object
With wsMaster
erow = .Range("A" & .Rows.Count).End(xlUp).Row 'get the last row
'~~> Copy from the file you opened
wsTemp.Range("A2:AD20").Copy 'you said this is fixed as well
'~~> Paste on your master sheet
.Range("A" & erow).Offset(1, 0).PasteSpecial xlPasteValues
End With
'~~> Close the opened file
wbTemp.Close False 'set to false, because we opened it as read-only
Set wsTemp = Nothing
Set wbTemp = Nothing
End If
'~~> Load the new file
MyFile = Dir
Loop
With Application
.ScreenUpdating = True
.DisplayAlerts = True
End With
End Sub
I've commented the code to help you modify it to suit your needs.
I you got stuck again, then just go back here and clearly state your problem.
Try this out:
Option Explicit
Sub CombineDataFiles()
Dim DataBook As Workbook, OutBook As Workbook
Dim DataSheet As Worksheet, OutSheet As Worksheet
Dim TargetFiles As FileDialog
Dim MaxNumberFiles As Long, FileIdx As Long, _
LastDataRow As Long, LastDataCol As Long, _
HeaderRow As Long, LastOutRow As Long
Dim DataRng As Range, OutRng As Range
'initialize constants
MaxNumberFiles = 2001
HeaderRow = 1 'assume headers are always in row 1
LastOutRow = 1
'prompt user to select files
Set TargetFiles = Application.FileDialog(msoFileDialogOpen)
With TargetFiles
.AllowMultiSelect = True
.Title = "Multi-select target data files:"
.ButtonName = ""
.Filters.Clear
.Filters.Add ".xlsx files", "*.xlsx"
.Show
End With
'error trap - don't allow user to pick more than 2000 files
If TargetFiles.SelectedItems.Count > MaxNumberFiles Then
MsgBox ("Too many files selected, please pick more than " & MaxNumberFiles & ". Exiting sub...")
Exit Sub
End If
'set up the output workbook
Set OutBook = Workbooks.Add
Set OutSheet = OutBook.Sheets(1)
'loop through all files
For FileIdx = 1 To TargetFiles.SelectedItems.Count
'open the file and assign the workbook/worksheet
Set DataBook = Workbooks.Open(TargetFiles.SelectedItems(FileIdx))
Set DataSheet = DataBook.ActiveSheet
'identify row/column boundaries
LastDataRow = DataSheet.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
LastDataCol = DataSheet.Cells.Find("*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
'if this is the first go-round, include the header
If FileIdx = 1 Then
Set DataRng = Range(DataSheet.Cells(HeaderRow, 1), DataSheet.Cells(LastDataRow, LastDataCol))
Set OutRng = Range(OutSheet.Cells(HeaderRow, 1), OutSheet.Cells(LastDataRow, LastDataCol))
'if this is NOT the first go-round, then skip the header
Else
Set DataRng = Range(DataSheet.Cells(HeaderRow + 1, 1), DataSheet.Cells(LastDataRow, LastDataCol))
Set OutRng = Range(OutSheet.Cells(LastOutRow + 1, 1), OutSheet.Cells(LastOutRow + 1 + LastDataRow, LastDataCol))
End If
'copy the data to the outbook
DataRng.Copy OutRng
'close the data book without saving
DataBook.Close False
'update the last outbook row
LastOutRow = OutSheet.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Next FileIdx
'let the user know we're done!
MsgBox ("Combined " & TargetFiles.SelectedItems.Count & " files!")
End Sub
Is there an alternative to using ActiveWorkbook and ActiveSheet in VBA when working with multiple workbooks (copying from workbooks in a list to a master sheet) ? It is turning out to be more confusing than anything to know which workbook is open when working with multiple functions which need to use different workbooks. Is it a matter of code organization ?
For the moment I think I can manage by storing the activeworkbook's name at the beginning of every function and restoring it, but it seems like a lot of work and probably a lot of processing time for not much results.
Ideas ?
You might be interested in this page http://www.techrepublic.com/blog/10things/10-ways-to-reference-excel-workbooks-and-sheets-using-vba/967
Specifically look at 4: Explicitly reference a workbook
Or 10: Refer to a sheet’s code name property
Typically when you work through a list you will use a workbook variable to open, manipulate and then close each book
My code below is an example of work through and collate a directory of workbooks (similar to your list example). From Collating worksheets from one or more workbooks into a summary file
Public Sub ConsolidateSheets()
Dim Wb1 As Workbook
Dim Wb2 As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Dim rng1 As Range
Dim rng2 As Range
Dim rng3 As Range
Dim rngArea As Range
Dim lrowSpace As Long
Dim lSht As Long
Dim lngCalc As Long
Dim lngRow As Long
Dim lngCol As Long
Dim X()
Dim bProcessFolder As Boolean
Dim bNewSheet As Boolean
Dim StrPrefix
Dim strFileName As String
Dim strFolderName As String
'variant declaration needed for the Shell object to use a default directory
Dim strDefaultFolder As Variant
bProcessFolder = (MsgBox("Process a single folder (Yes)," & vbNewLine & "or single file (No)", vbYesNo, "Application Scope: Folder or single File") = vbYes)
bNewSheet = (MsgBox("Extract all data to a single sheet (Yes)," & vbNewLine & "or a target file sheet for each source sheet (No)", vbYesNo, "Output Format: Single sheet or sheet by sheet collection") = vbYes)
If Not bProcessFolder Then
If Not bNewSheet Then
MsgBox "There isn't much point creating a exact replica of your source file :)"
Exit Sub
End If
End If
'set default directory here if needed
strDefaultFolder = "C:\temp"
'If the user is collating all the sheets to a single target sheet then the row spacing
'to distinguish between different sheets can be set here
lrowSpace = 1
If bProcessFolder Then
strFolderName = BrowseForFolder(strDefaultFolder)
'Look for xls, xlsx, xlsm files
strFileName = Dir(strFolderName & "\*.xls*")
Else
strFileName = Application _
.GetOpenFilename("Select file to process (*.xls*), *.xls*")
End If
Set Wb1 = Workbooks.Add(1)
Set ws1 = Wb1.Sheets(1)
If Not bNewSheet Then ws1.Range("A1:B1") = Array("workbook name", "worksheet count")
'Turn off screenupdating, events, alerts and set calculation to manual
With Application
.DisplayAlerts = False
.EnableEvents = False
.ScreenUpdating = False
lngCalc = .Calculation
.Calculation = xlCalculationManual
End With
'set path outside the loop
StrPrefix = strFolderName & IIf(bProcessFolder, "\", vbNullString)
Do While Len(strFileName) > 0
'Provide progress status to user
Application.StatusBar = Left("Processing " & strFolderName & "\" & strFileName, 255)
'Open each workbook in the folder of interest
Set Wb2 = Workbooks.Open(StrPrefix & strFileName)
If Not bNewSheet Then
'add summary details to first sheet
ws1.Cells(Rows.Count, "A").End(xlUp).Offset(1, 0) = Wb2.Name
ws1.Cells(Rows.Count, "A").End(xlUp).Offset(0, 1) = Wb2.Sheets.Count
End If
For Each ws2 In Wb2.Sheets
If bNewSheet Then
'All data to a single sheet
'Skip importing target sheet data if the source sheet is blank
Set rng2 = ws2.Cells.Find("*", ws2.[a1], xlValues, , xlByRows, xlPrevious)
If Not rng2 Is Nothing Then
Set rng1 = ws1.Cells.Find("*", ws1.[a1], xlValues, , xlByRows, xlPrevious)
'Find the first blank row on the target sheet
If Not rng1 Is Nothing Then
Set rng3 = ws2.Range(ws2.UsedRange.Cells(1), ws2.Cells(rng2.Row, "A"))
'Ensure that the row area in the target sheet won't be exceeded
If rng3.Rows.Count + rng1.Row < Rows.Count Then
'Copy the data from the used range of each source sheet to the first blank row
'of the target sheet, using the starting column address from the source sheet being copied
ws2.UsedRange.Copy ws1.Cells(rng1.Row + 1 + lrowSpace, ws2.UsedRange.Cells(1).Column)
Else
MsgBox "Summary sheet size exceeded. Process stopped on " & vbNewLine & _
"sheet: " & ws2.Name & vbNewLine & "of" & vbNewLine & "workbook: " & Wb2.Name
Wb2.Close False
Exit Do
End If
'colour the first of any spacer rows
If lrowSpace <> 0 Then ws1.Rows(rng1.Row + 1).Interior.Color = vbGreen
Else
'target sheet is empty so copy to first row
ws2.UsedRange.Copy ws1.Cells(1, ws2.UsedRange.Cells(1).Column)
End If
End If
Else
'new target sheet for each source sheet
ws2.Copy after:=Wb1.Sheets(Wb1.Sheets.Count)
'Remove any links in our target sheet
With Wb1.Sheets(Wb1.Sheets.Count).Cells
.Copy
.PasteSpecial xlPasteValues
End With
On Error Resume Next
Wb1.Sheets(Wb1.Sheets.Count).Name = ws2.Name
'sheet name already exists in target workbook
If Err.Number <> 0 Then
'Add a number to the sheet name till a unique name is derived
Do
lSht = lSht + 1
Set ws3 = Wb1.Sheets(ws2.Name & " " & lSht)
Loop While Not ws3 Is Nothing
lSht = 0
End If
On Error GoTo 0
End If
Next ws2
'Close the opened workbook
Wb2.Close False
'Check whether to force a DO loop exit if processing a single file
If bProcessFolder = False Then Exit Do
strFileName = Dir
Loop
'Remove any links if the user has used a target sheet
If bNewSheet Then
With ws1.UsedRange
.Copy
.Cells(1).PasteSpecial xlPasteValues
.Cells(1).Activate
End With
Else
'Format the summary sheet if the user has created separate target sheets
ws1.Activate
ws1.Range("A1:B1").Font.Bold = True
ws1.Columns.AutoFit
End If
With Application
.CutCopyMode = False
.DisplayAlerts = True
.EnableEvents = True
.ScreenUpdating = True
.Calculation = lngCalc
.StatusBar = vbNullString
End With
End Sub
Function BrowseForFolder(Optional OpenAt As Variant) As Variant
'From Ken Puls as used in his vbaexpress.com article
'http://www.vbaexpress.com/kb/getarticle.php?kb_id=284
Dim ShellApp As Object
'Create a file browser window at the default folder
Set ShellApp = CreateObject("Shell.Application"). _
BrowseForFolder(0, "Please choose a folder", 0, OpenAt)
'Set the folder to that selected. (On error in case cancelled)
On Error Resume Next
BrowseForFolder = ShellApp.self.Path
On Error GoTo 0
'Destroy the Shell Application
Set ShellApp = Nothing
'Check for invalid or non-entries and send to the Invalid error
'handler if found
'Valid selections can begin L: (where L is a letter) or
'\\ (as in \\servername\sharename. All others are invalid
Select Case Mid(BrowseForFolder, 2, 1)
Case Is = ":"
If Left(BrowseForFolder, 1) = ":" Then GoTo Invalid
Case Is = "\"
If Not Left(BrowseForFolder, 1) = "\" Then GoTo Invalid
Case Else
GoTo Invalid
End Select
Exit Function
Invalid:
'If it was determined that the selection was invalid, set to False
BrowseForFolder = False
End Function
I have a template file which will be sent out to all subsidiaries of my company.
The template has a tab named start and one named end.
The subsidiaries will place a variable number of template submission sheets between these two names sheets and send them in to me to consolidate into one sheet in my consolidation file.
I have written macros to copy each sheet into the consolidation file, but I currently need to run it sheet by sheet as I don't know how to loop.
The copy macro sits in my Personal.xls file and the paste macro sits in the consolidation sheet.
The loop macro would need to work between the Source file (could be any name) and the consolidation file which is called Consolidation.xls.
Once all sheets are copied from a source file, I then open the next source file and start again, so macro would need to forget the old source file and remember the new one.
This could literally save me hours each week if I could get a macro to work, so any help much appreciated.
I think this is along the lines of what you are chasing. If all your templates are in a single folder, and each have a "start" and "end" sheet then this code will collate them into either
A new workbook with a unique sheet for each relevant sheet in each template
Into a single sheet in a new workbook
I have updated my code from "Collating worksheets from one or more workbooks into a summary file", http://www.experts-exchange.com/A_2804.html to cater for your "start" and "end" sheets
Please post if you need (or have) further detail
Public Sub ConsolidateSheets()
Dim Wb1 As Workbook
Dim Wb2 As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Dim rng1 As Range
Dim rng2 As Range
Dim rng3 As Range
Dim rngArea As Range
Dim lrowSpace As Long
Dim lSht As Long
Dim lngCalc As Long
Dim lngRow As Long
Dim lngCol As Long
Dim X()
Dim bProcessFolder As Boolean
Dim bNewSheet As Boolean
Dim StrPrefix
Dim strFileName As String
Dim strFolderName As String
'variant declaration needed for the Shell object to use a default directory
Dim strDefaultFolder As Variant
bProcessFolder = (MsgBox("Process a single folder (Yes)," & vbNewLine & "or single file (No)", vbYesNo, "Application Scope: Folder or single File") = vbYes)
bNewSheet = (MsgBox("Extract all data to a single sheet (Yes)," & vbNewLine & "or a target file sheet for each source sheet (No)", vbYesNo, "Output Format: Single sheet or sheet by sheet collection") = vbYes)
If Not bProcessFolder Then
If Not bNewSheet Then
MsgBox "There isn't much point creating a exact replica of your source file :)"
Exit Sub
End If
End If
'set default directory here if needed
strDefaultFolder = "C:\"
'If the user is collating all the sheets to a single target sheet then the row spacing
'to distinguish between different sheets can be set here
lrowSpace = 1
If bProcessFolder Then
strFolderName = BrowseForFolder(strDefaultFolder)
'Look for xls, xlsx, xlsm files
strFileName = Dir(strFolderName & "\*.xls*")
Else
strFileName = Application _
.GetOpenFilename("Select file to process (*.xls*), *.xls*")
End If
Set Wb1 = Workbooks.Add(1)
Set ws1 = Wb1.Sheets(1)
If Not bNewSheet Then ws1.Range("A1:B1") = Array("workbook name", "worksheet count")
'Turn off screenupdating, events, alerts and set calculation to manual
With Application
.DisplayAlerts = False
.EnableEvents = False
.ScreenUpdating = False
lngCalc = .Calculation
.Calculation = xlCalculationManual
End With
'set path outside the loop
StrPrefix = strFolderName & IIf(bProcessFolder, "\", vbNullString)
Do While Len(strFileName) > 0
'Provide progress status to user
Application.StatusBar = Left("Processing " & strFolderName & "\" & strFileName, 255)
'Open each workbook in the folder of interest
Set Wb2 = Workbooks.Open(StrPrefix & strFileName)
If Not bNewSheet Then
'add summary details to first sheet
ws1.Cells(Rows.Count, "A").End(xlUp).Offset(1, 0) = Wb2.Name
ws1.Cells(Rows.Count, "A").End(xlUp).Offset(0, 1) = Wb2.Sheets.Count
End If
For Each ws2 In Wb2.Sheets
If ws2.Index > Wb2.Sheets("start").Index And ws2.Index < Wb2.Sheets("end").Index Then
If bNewSheet Then
'All data to a single sheet
'Skip importing target sheet data if the source sheet is blank
Set rng2 = ws2.Cells.Find("*", ws2.[a1], xlValues, , xlByRows, xlPrevious)
If Not rng2 Is Nothing Then
Set rng1 = ws1.Cells.Find("*", ws1.[a1], xlValues, , xlByRows, xlPrevious)
'Find the first blank row on the target sheet
If Not rng1 Is Nothing Then
Set rng3 = ws2.Range(ws2.UsedRange.Cells(1), ws2.Cells(rng2.Row, "A"))
'Ensure that the row area in the target sheet won't be exceeded
If rng3.Rows.Count + rng1.Row < Rows.Count Then
'Copy the data from the used range of each source sheet to the first blank row
'of the target sheet, using the starting column address from the source sheet being copied
ws2.UsedRange.Copy ws1.Cells(rng1.Row + 1 + lrowSpace, ws2.UsedRange.Cells(1).Column)
Else
MsgBox "Summary sheet size exceeded. Process stopped on " & vbNewLine & _
"sheet: " & ws2.Name & vbNewLine & "of" & vbNewLine & "workbook: " & Wb2.Name
Wb2.Close False
Exit Do
End If
'colour the first of any spacer rows
If lrowSpace <> 0 Then ws1.Rows(rng1.Row + 1).Interior.Color = vbGreen
Else
'target sheet is empty so copy to first row
ws2.UsedRange.Copy ws1.Cells(1, ws2.UsedRange.Cells(1).Column)
End If
End If
Else
'new target sheet for each source sheet
ws2.Copy after:=Wb1.Sheets(Wb1.Sheets.Count)
'Remove any links in our target sheet
With Wb1.Sheets(Wb1.Sheets.Count).Cells
.Copy
.PasteSpecial xlPasteValues
End With
On Error Resume Next
Wb1.Sheets(Wb1.Sheets.Count).Name = ws2.Name
'sheet name already exists in target workbook
If Err.Number <> 0 Then
'Add a number to the sheet name till a unique name is derived
Do
lSht = lSht + 1
Set ws3 = Wb1.Sheets(ws2.Name & " " & lSht)
Loop While Not ws3 Is Nothing
lSht = 0
End If
On Error GoTo 0
End If
End If
Next ws2
'Close the opened workbook
Wb2.Close False
'Check whether to force a DO loop exit if processing a single file
If bProcessFolder = False Then Exit Do
strFileName = Dir
Loop
'Remove any links if the user has used a target sheet
If bNewSheet Then
With ws1.UsedRange
.Copy
.Cells(1).PasteSpecial xlPasteValues
.Cells(1).Activate
End With
Else
'Format the summary sheet if the user has created separate target sheets
ws1.Activate
ws1.Range("A1:B1").Font.Bold = True
ws1.Columns.AutoFit
End If
With Application
.CutCopyMode = False
.DisplayAlerts = True
.EnableEvents = True
.ScreenUpdating = True
.Calculation = lngCalc
.StatusBar = vbNullString
End With
End Sub
Function BrowseForFolder(Optional OpenAt As Variant) As Variant
'From Ken Puls as used in his vbaexpress.com article
'http://www.vbaexpress.com/kb/getarticle.php?kb_id=284
Dim ShellApp As Object
'Create a file browser window at the default folder
Set ShellApp = CreateObject("Shell.Application"). _
BrowseForFolder(0, "Please choose a folder", 0, OpenAt)
'Set the folder to that selected. (On error in case cancelled)
On Error Resume Next
BrowseForFolder = ShellApp.self.Path
On Error GoTo 0
'Destroy the Shell Application
Set ShellApp = Nothing
'Check for invalid or non-entries and send to the Invalid error
'handler if found
'Valid selections can begin L: (where L is a letter) or
'\\ (as in \\servername\sharename. All others are invalid
Select Case Mid(BrowseForFolder, 2, 1)
Case Is = ":"
If Left(BrowseForFolder, 1) = ":" Then GoTo Invalid
Case Is = "\"
If Not Left(BrowseForFolder, 1) = "\" Then GoTo Invalid
Case Else
GoTo Invalid
End Select
Exit Function
Invalid:
'If it was determined that the selection was invalid, set to False
BrowseForFolder = False
End Function
You should show us some code if you really want help.
But as far as I understood your question, here are some tips or links.
Code snippet to loop over worksheets
Dim wkbkorigin As Workbook
Dim ws As Worksheet
Set wkbkorigin = Workbooks.Open("C:\bookB.xls")
For Each ws In wkbkorigin.Worksheets
'do whatever
Next
Some stackoverflow threads about this issue
excel vba loop through worksheets and set values according to input
How can I loop through a subset of worksheets?
Some more tips about getting info from files
See this valuable thread: Copy data from another Workbook through VBA
You will find info about:
how to use the Excel object model to copy data from a file to another
using GetInfoFromClosedFile() function
Once you've defined workbooks/worksheets as per JMax response, I think you're looking for the following...
IncludeSheet=0
For n = 1 to wkbkOrigin.Worksheets.Count
If wkbkOrigin.Sheets(n).Name = "End" Then
IncludeSheet = 0
End If
If IncludeSheet = 1 Then
Set ws = wkbkOrigin.Sheets(n)
'do whatever
End If
If wkbkOrigin.Sheets(n).Name = "Start" Then
IncludeSheet = 1
End If
Next n
The key is to introduce a flag variable to tell you if you're in the right part of the workbook, in this case IncludeSheet