Copy different ranges when looping through workbooks - vba

With the following code i am able to browse for multiple excel file's at the same time and paste them on single sheet below each other so my problem is it copies everything including their headers but the thing is i only want it to copy the first file with headers and the rest it must copy only data not headers and paste it below each other because all their headers are the same.
example:eg1 NAME,SURNAME,AGE
Kgotso,Smith,20
eg2 NAME,SURNAME,AGE
brian,brown,32
Result : NAME,SURNAME,AGE
Kgotso,Smith,20
brian,brown,32
Sub Button4_Click()
Dim fileStr As Variant
Dim wbk1 As Workbook, wbk2 As Workbook
Dim ws1 As Worksheet
fileStr = Application.GetOpenFilename(FileFilter:="microsoft excel files (*.xlsx), *.xlsx", Title:="Get File", MultiSelect:=True)
Set wbk1 = ActiveWorkbook
Set ws1 = wbk1.Sheets("Sheet3")
For i = 1 To UBound(fileStr)
MsgBox fileStr(i), , GetFileName(CStr(fileStr(i)))
Set wbk2 = Workbooks.Open(fileStr(i))
wbk2.Sheets(1).UsedRange.Copy ws1.Cells(ws1.Range("A" & Rows.Count).End(xlUp).Row + 2, 1)
wbk2.Close
Next i
End Sub

This would be my quick attempt to this:
Sub Button4_Click()
Dim fileStr As Variant
Dim wbk1 As Workbook, wbk2 As Workbook
Dim ws1 As Worksheet
fileStr = Application.GetOpenFilename(FileFilter:="microsoft excel files (*.xlsx), *.xlsx", Title:="Get File", MultiSelect:=True)
Set wbk1 = ActiveWorkbook
Set ws1 = wbk1.Sheets("Sheet3")
'handling first file seperately
MsgBox fileStr(1), , GetFileName(CStr(fileStr(1)))
Set wbk2 = Workbooks.Open(fileStr(1))
wbk2.Sheets(1).UsedRange.Copy ws1.Cells(ws1.Range("A" & Rows.Count).End(xlUp).Row + 2, 1)
wbk2.Close
For i = 2 To UBound(fileStr)
MsgBox fileStr(i), , GetFileName(CStr(fileStr(i)))
Set wbk2 = Workbooks.Open(fileStr(i))
'using offset to skip the header - not the best solution, but a quick one
wbk2.Sheets(1).UsedRange.Offset(1,0).Copy ws1.Cells(ws1.Range("A" & Rows.Count).End(xlUp).Row + 2, 1)
wbk2.Close
Next i
End Sub

Try this
If i = 1 then
' Do your copy as is
Else
' Offset past firt row
wbk2.Sheets(1).UsedRange.Offset(1, 0).Copy ...
' This will copy one blank line too
' Too avoid this extra line use instead
Set rng2 = wbk2.Sheets(1).UsedRange.Offset(1, 0)
Set rng2 = rng2.Resize(rng2.Rows.Count - 1)
rng2.Copy ...
End If

Related

Combining Excel workbooks, but need the all worksheets, not just the first

I found this VBA code that works for combining workbooks in a folder, however, I need to modify it so that all worksheets in each workbook are copy/pasted and not just the first worksheet of each workbook. As of now, only the first worksheet in each selected workbook is being copied over. Where can I insert code to find data in all worksheets?
Thanks!
Sub MergeSelectedWorkbooks()
Dim SummarySheet As Worksheet
Dim FolderPath As String
Dim SelectedFiles() As Variant
Dim NRow As Long
Dim FileName As String
Dim NFile As Long
Dim WorkBk As Workbook
Dim SourceRange As Range
Dim DestRange As Range
' Create a new workbook and set a variable to the first sheet.
Set SummarySheet = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
' Modify this folder path to point to the files you want to use.
FolderPath = "S:\example"
' Set the current directory to the the folder path.
ChDrive FolderPath
ChDir FolderPath
' Open the file dialog box and filter on Excel files, allowing multiple files
' to be selected.
SelectedFiles = Application.GetOpenFilename( _
filefilter:="Excel Files (*.xl*), *.xl*", MultiSelect:=True)
' NRow keeps track of where to insert new rows in the destination workbook.
NRow = 1
' Loop through the list of returned file names
For NFile = LBound(SelectedFiles) To UBound(SelectedFiles)
' Set FileName to be the current workbook file name to open.
FileName = SelectedFiles(NFile)
' Open the current workbook.
Set WorkBk = Workbooks.Open(FileName)
Dim LastRow As Long
LastRow = WorkBk.Worksheets(1).Cells.Find(What:="*", _
After:=WorkBk.Worksheets(1).Cells.Range("A1"), _
SearchDirection:=xlPrevious, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows).Row
Set SourceRange = WorkBk.Worksheets(1).Range("A1:Z" & LastRow)
' Set the destination range to start at column A and be the same size as the source range.
Set DestRange = SummarySheet.Range("A" & NRow)
Set DestRange = DestRange.Resize(SourceRange.Rows.Count, _
SourceRange.Columns.Count)
' Copy over the values from the source to the destination.
DestRange.Value = SourceRange.Value
' Increase NRow so that we know where to copy data next.
NRow = NRow + DestRange.Rows.Count
' Close the source workbook without saving changes.
WorkBk.Close savechanges:=False
Next NFile
' Call AutoFit on the destination sheet so that all data is readable.
SummarySheet.Columns.AutoFit
End Sub
Opens multiple workbooks (1 by 1), Copies data from all sheets onto one sheet. Make sure you modify the ranges that will work for you (copy range is currently A2 to Z(last row).
Option Explicit
Sub MoveSheets()
Dim IndvFiles As FileDialog
Dim Currentbook As Workbook
Dim x As Integer
Dim i As Integer
Dim CurrentSheets As Integer
Dim BookCount As Integer
'Opens File Dialog to Select Which Files You Want to Consolidate
Set IndvFiles = Application.FileDialog(msoFileDialogOpen)
With IndvFiles
.AllowMultiSelect = True
.Title = "Multi-select target data files:"
.ButtonName = ""
.Filters.Clear
.Show
End With
Application.ScreenUpdating = False
Application.DisplayAlerts = False
CurrentSheets = ThisWorkbook.Worksheets.Count
BookCount = IndvFiles.SelectedItems.Count
Dim LROW as Long
DIM LROW2 as Long
DIM Import as Range
For x = 1 To BookCount
On Error GoTo StopHere:
Set Currentbook = Workbooks.Open(IndvFiles.SelectedItems(X))
For i = 1 To Currentbook.Worksheets.Count
LROW = thisworkbook.sheets("desired sheet name paste").Range("A2").End(XLdown).Rows
LROW2=currentbook.sheets(i).Range("A2").End(XLdown).Rows
Set Import = currentbook.sheets(i).Range("A2:Z"&LROW2)
Import.Copy
ThisWorkbook.Sheets("Desired sheet name paste range").Range("A"&LROW).PasteSpecial Paste:=xlPasteValues, operation:=xlNone, skipblanks _
Next i
Currentbook.Close False
Next x
StopHere:
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub

Looping through files in a folder, copy contents to specific sheet and loop through sheets in master file

Before starting to explain my problem, sorry for the messy code, I'm still a beginner in VBA and thank you for your help in advance.
So what I'm trying to do is getting a way of copying the contents of some workbooks in a folder to my master file, which is kinda like a data base. The trick here is that I need the 2 sheets from the file to be copied into the 1st sheet of my master file.
In the mean time and looking through a lot of posts, like this one,
VBA Loop through files in folder and copy/paste to master file, I came up with this code:
Option Explicit
Sub AllFiles()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.EnableEvents = False
Application.EnableCancelKey = xlDisabled
Application.ScreenUpdating = False
Dim folderPath As String
Dim Filename As String
Dim wb As Workbook
Dim Masterwb As Workbook
Dim sh As Worksheet
Dim NewSht As Worksheet
Dim FindRng As Range
Dim PasteRow As Long
Dim i As Integer
' set master workbook
Set Masterwb = ThisWorkbook
folderPath = Sheets("teste").Range("A1").Value 'contains folder path
If Right(folderPath, 1) <> "\" Then folderPath = folderPath & "\"
For i = 1 To Sheets("leit_func").Range("S2")
Filename = Dir(folderPath & Sheets("teste").Range("A3"))
Do While Filename <> ""
Set wb = Workbooks.Open(folderPath & Filename)
If Len(wb.Name) > 35 Then
MsgBox "Sheet's name can be up to 31 characters long, shorten the Excel file name"
wb.Close False
GoTo Exit_Loop
Else
' add a new sheet with the file's name (remove the extension)
'-------------------------------------------------------------------------------------------
'Set NewSht = Masterwb.Worksheets.Add(After:=Masterwb.Worksheets(1))
'NewSht.Name = Replace(wb.Name, ".xlsx", "")
'-------------------------------------------------------------------------------------------
Set NewSht = ThisWorkbook.Sheets(i)
End If
' loop through all sheets in opened wb
For Each sh In wb.Worksheets
' get the first empty row in the new sheet
Set FindRng = NewSht.Cells.Find(What:="*", Lookat:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False)
If Not FindRng Is Nothing Then ' If find is successful
PasteRow = FindRng.Row + 1
Else ' find was unsuccessfull > new empty sheet, should paste at the first row
PasteRow = 1
End If
sh.UsedRange.Copy
NewSht.Range("A" & PasteRow).PasteSpecial xlPasteValues
'NewSht.PasteSpecial Paste:=xlPasteValuesAndNumberFormats, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=False
Next sh
wb.Close False
Exit_Loop:
Set wb = Nothing
Filename = Dir()
Loop
Next i
Application.ScreenUpdating = True
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.EnableEvents = False
End Sub
With this code I can paste the info in different sheets, but the problem is that it's getting the contents from all the files in the folder, and I want file 1 in sheet 1, file 2 in sheet 2, and so on.
I think my problem has something to do with the placement of my For cycle for the sheets, but I'm not exactly sure.
Thank you!
Here is a copy/paste from a script library i keep. It is a rough example of how to loop through files in a directory and copy and paste each sheet to a new sheet in the master workbook. I have included a section that shows how to append to the end of a range as well. Both can be useful. Note that i use arrays to move data as its easier and faster.
Public Sub this()
Dim path As String, fileName As String, shtName As String
Dim sheet As Worksheet, thisWB As Workbook, thatWB As Workbook
Dim arr() As Variant
Dim rowC As Long, colC As Long, mrowC As Long, mColC As Long
path = "your path to directory" & "\"
fileName = Dir(path & "*.xl??")
Set thisWB = ThisWorkbook
Do While Len(fileName) > 0
Set thatWB = Workbooks.Open(path & fileName, True, True)
For Each sheet In thatWB.Sheets
shtName = Left(Mid(fileName, 1, InStrRev(fileName, ".") - 1), 30)
thisWB.ActiveSheet.Name = shtName
mrowC = thisWB.Sheets(shtName).UsedRange.Rows.Count
mColC = thisWB.Sheets(shtName).UsedRange.Columns.Count
arr = sheet.UsedRange
rowC = sheet.UsedRange.Rows.Count
colC = sheet.UsedRange.Columns.Count
thisWB.Sheets(shtName).Range(thisWB.Sheets(shtName).Cells(mrowC + 1, 1), thisWB.Sheets(shtName).Cells(mrowC + 1 + rowC, colC)).Value2 = arr
Next sheet
thatWB.Close False
fileName = Dir()
thisWB.Sheets.Add After:=Worksheets(Worksheets.Count)
Loop
End Sub

Automatically update macro when changing filename

I have the following macro to filter specific data out of my directory with employee hours files and place it into my zmaster file. However, I need various master documents for various projects (EG. change name to: "project 300000"). When I change my master file name from zmaster to anything else, my macro cannot find the appropriate file, obviously.
Is there a way to change my macro in such a way that zmaster.xlsm is automatically replaced in my macro by the current file name?
Option Explicit
Sub CopyToMasterFile()
Dim MasterWB As Workbook
Dim MasterSht As Worksheet
Dim MasterWBShtLstRw As Long
Dim FolderPath As String
Dim TempFile
Dim CurrentWB As Workbook
Dim CurrentWBSht As Worksheet
Dim CurrentShtLstRw As Long
Dim CurrentShtRowRef As Long
Dim CopyRange As Range
Dim ProjectNumber As String
FolderPath = "C:\test\"
TempFile = Dir(FolderPath)
Dim WkBk As Workbook
Dim WkBkIsOpen As Boolean
'Check if zmaster is open already
For Each WkBk In Workbooks
If WkBk.Name = "zmaster.xlsm" Then WkBkIsOpen = True
Next WkBk
If WkBkIsOpen Then
Set MasterWB = Workbooks("zmaster.xlsm")
Set MasterSht = MasterWB.Sheets("Sheet1")
Else
Set MasterWB = Workbooks.Open(FolderPath & "zmaster.xlsm")
Set MasterSht = MasterWB.Sheets("Sheet1")
End If
ProjectNumber = MasterSht.Cells(1, 1).Value
Do While Len(TempFile) > 0
'Checking that the file is not the master and that it is a xlsx
If Not TempFile = "zmaster.xlsm" And InStr(1, TempFile, "xlsx", vbTextCompare) Then
Set CopyRange = Nothing
'Note this is the last used Row, next empty row will be this plus 1
With MasterSht
MasterWBShtLstRw = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Set CurrentWB = Workbooks.Open(FolderPath & TempFile)
Set CurrentWBSht = CurrentWB.Sheets("Sheet1")
With CurrentWBSht
CurrentShtLstRw = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
For CurrentShtRowRef = 1 To CurrentShtLstRw
If CurrentWBSht.Cells(CurrentShtRowRef, "A").Value = ProjectNumber Then
'This is set to copy from Column A to Column L as per the question
If CopyRange Is Nothing Then
'If there is nothing in Copy range then union wont work
'so first row of the work sheet needs to set the initial copyrange
Set CopyRange = CurrentWBSht.Range("A" & CurrentShtRowRef & _
":L" & CurrentShtRowRef)
Else
'Union is quicker to be able to copy from the sheet once
Set CopyRange = Union(CopyRange, _
CurrentWBSht.Range("A" & CurrentShtRowRef & _
":L" & CurrentShtRowRef))
End If ' ending If CopyRange Is Nothing ....
End If ' ending If CurrentWBSht.Cells....
Next CurrentShtRowRef
CopyRange.Select
'add 1 to the master file last row to be the next open row
CopyRange.Copy MasterSht.Cells(MasterWBShtLstRw + 1, 1)
CurrentWB.Close savechanges:=False
End If 'ending If Not TempFile = "zmaster.xlsx" And ....
TempFile = Dir
Loop
ActiveSheet.Range("A1:L200").RemoveDuplicates Columns:=Array(1, 2, 4, 8, 9, 10, 11, 12), Header:=xlYes
End Sub
One way to escape from hard coded workbook names is to use ActiveWorkbook or ThisWorkbook objects - they both return instance of Workbook object.
ThisWorkbook
Returns a Workbook object that represents the workbook
where the current macro code is running. Read-only.
ActiveWorkbook
Returns a Workbook object that represents the workbook in the active
window (the window on top). Read-only. Returns Nothing if there are no
windows open or if either the Info window or the Clipboard window is
the active window.
Then you can get the name of the workbook with Name property of the returned Workbook object.
Another way could be if you pass such a data as parameter to your functions.
For example:
Sub CopyToMasterFile(wbName as String, sheetName as String)
In this variant if you call your Sub from another macro code, you can pass whatever you want to use - this ways you can escape the hard coded stuff in your functions.
This is also valid for the Worksheet objects - have a look on the ActiveSheet

Excel adjust to non-active worksheets while looping through directory

I have the following macro to loop through directory and put data in my master file. The masterfolder contains all information about employee hours spend on a specific project. However, the sheet name of the employee hour files (non-master files) might differ. I managed to change this for the activesheet (master sheet) but I'm not sure how to adjust this for the non-active (non-master) sheets (in formula this specific sentence: Set CurrentWBSht = CurrentWB.Sheets("Sheet1")
Option Explicit
Sub CopyToMasterFile()
Dim MasterWB As Workbook
Dim MasterSht As Worksheet
Dim MasterWBShtLstRw As Long
Dim FolderPath As String
Dim TempFile
Dim CurrentWB As Workbook
Dim CurrentWBSht As Worksheet
Dim CurrentShtLstRw As Long
Dim CurrentShtRowRef As Long
Dim CopyRange As Range
Dim ProjectNumber As String
Dim wbname As String
Dim sheetname As String
wbname = ActiveWorkbook.Name
sheetname = ActiveSheet.Name
FolderPath = "C:\test file\"
TempFile = Dir(FolderPath)
Dim WkBk As Workbook
Dim WkBkIsOpen As Boolean
'Check is master is open already
For Each WkBk In Workbooks
If WkBk.Name = wbname Then WkBkIsOpen = True
Next WkBk
If WkBkIsOpen Then
Set MasterWB = Workbooks(wbname)
Set MasterSht = MasterWB.Sheets(sheetname)
Else
Set MasterWB = Workbooks.Open(FolderPath & wbname)
Set MasterSht = MasterWB.Sheets(sheetname)
End If
ProjectNumber = MasterSht.Cells(1, 1).Value
Do While Len(TempFile) > 0
'Checking that the file is not the master and that it is a xlsx
If Not TempFile = wbname And InStr(1, TempFile, "xlsx", vbTextCompare) Then
Set CopyRange = Nothing
'Note this is the last used Row, next empty row will be this plus 1
With MasterSht
MasterWBShtLstRw = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Set CurrentWB = Workbooks.Open(FolderPath & TempFile)
Set CurrentWBSht = CurrentWB.Sheets("Sheet1")
With CurrentWBSht
CurrentShtLstRw = .Cells(.Rows.Count, "AE").End(xlUp).Row
End With
For CurrentShtRowRef = 1 To CurrentShtLstRw
If CurrentWBSht.Cells(CurrentShtRowRef, "AE").Value = ProjectNumber Then
'This is set to copy from Column A to Column L as per the question
If CopyRange Is Nothing Then
'If there is nothing in Copy range then union wont work
'so first row of the work sheet needs to set the initial copyrange
Set CopyRange = CurrentWBSht.Range("AE" & CurrentShtRowRef & _
":AQ" & CurrentShtRowRef)
Else
'Union is quicker to be able to copy from the sheet once
Set CopyRange = Union(CopyRange, _
CurrentWBSht.Range("AE" & CurrentShtRowRef & _
":AQ" & CurrentShtRowRef))
End If ' ending If CopyRange Is Nothing ....
End If ' ending If CurrentWBSht.Cells....
Next CurrentShtRowRef
CopyRange.Select
'add 1 to the master file last row to be the next open row
CopyRange.Copy
MasterSht.Cells(MasterWBShtLstRw + 1, 1).PasteSpecial xlPasteValues
CurrentWB.Close savechanges:=False
End If 'ending If Not TempFile = "master.xlsx" And ....
TempFile = Dir
Loop
ActiveSheet.Range("A1:M200").RemoveDuplicates Columns:=Array(1, 2, 4, 8, 9, 10, 11, 12), Header:=xlYes
End Sub
There are a few ways to refer to a worksheet, without knowing their names in advance:
'To get a specific worksheet:
Set CurrentWBSht = CurrentWB.Worksheets(10)
'To get the last worksheet:
Set CurrentWBSht = CurrentWB.Worksheets(Worksheets.Count)
'To get the pre last worksheet:
Set CurrentWBSht = CurrentWB.Worksheets(Worksheets.Count-1)
If the workbook only has 1 sheet then you can simply do this:
Set CurrentWBSht = CurrentWB.Sheets(1)
If there are more than 1 sheet in the 'non-master' workbook, you could have this:
Set CurrentWB = Workbooks.Open(FolderPath & TempFile)
Dim oWS As Worksheet
' Loop through all sheets to find the sheet we want
For Each oWS In CurrentWB.Worksheets
If oWS.Name = sheetname Then
Set CurrentWBSht = oWS
Exit For
End If
Next
You could add a flag in the loop above to confirm if you found a sheet
Also, from what I can see, your macro is in your master sheet?. If that's the case, you don't need to do the check if the 'Master workbook' is open. You can just use ThisWorkbook.Worksheets(1).Name (ThisWorkbook is the object for the workbook where your macro is running from)

How to copy and append cells content from a different workbook to an Activework?

I have a macro that allows a user to browse and select multiple Excel files, after the user has selected the multiple Excel files, the content from multiple Excel files should be saved on the current active workbook, on one sheet. the content would be append one another.
The problem is that when the loop runs for the second time it complains with the range, it says the range should start at "A1".
here is my code below.
Sub Button3_Click()
Dim fileStr As Variant
Dim incount As Integer
Dim wbk1 As Workbook, wbk2 As Workbook
incount = 1
fileStr = Application.GetOpenFilename(FileFilter:="microsoft excel files (*.xlsx), *.xlsx", Title:="Get File", MultiSelect:=True)
For i = 1 To UBound(fileStr)
MsgBox fileStr(i), , GetFileName(CStr(fileStr(i)))
Set wbk1 = ActiveWorkbook
Set wbk2 = Workbooks.Open(fileStr(i))
wbk2.Sheets(1).Cells.Copy wbk1.Worksheets("Sheet3").Cells(incount, 1)
incount = Range("A" & Rows.Count).End(xlUp).Row
wbk2.Close
Next i
MsgBox incount
End Sub
Function GetFileName(fileStr As String)
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
GetFileName = fso.GetFileName(fileStr)
End Function
Error message:
Run-time error '1004'
To paste all cells from an Excel worksheet into the current worksheet,
you must paste into the first cell(A1 or R1C1)
The cells.copy copies the whole sheet of data to the row of 'incount' which means that there is not room on the destination for the 'whole source sheet' below the already pasted data
Try the following code which removes incount and just picks up the UsedRange:
Sub Button3_Click()
Dim fileStr As Variant
Dim wbk1 As Workbook, wbk2 As Workbook
Dim ws1 As Worksheet
fileStr = Application.GetOpenFilename(FileFilter:="microsoft excel files (*.xlsx), *.xlsx", Title:="Get File", MultiSelect:=True)
Set wbk1 = ActiveWorkbook
Set ws1 = wbk1.Sheets("Sheet3")
For i = 1 To UBound(fileStr)
MsgBox fileStr(i), , GetFileName(CStr(fileStr(i)))
Set wbk2 = Workbooks.Open(fileStr(i))
wbk2.Sheets(1).UsedRange.Copy ws1.Cells(ws1.Range("A" & Rows.Count).End(xlUp).Row + 1, 1)
wbk2.Close
Next i
End Sub
Function GetFileName(fileStr As String)
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
GetFileName = fso.GetFileName(fileStr)
End Function