A family of Microsoft spreadsheet software with tools for analyzing, charting, and communicating data.
The code example below loops through all worksheets. Best to have the worksheets to be skipped in a worksheet and then the user does not need to be able to edit the VBA code to add sheets to be skipped. Therefore add a worksheet called "Exclude List" and insert the list of worksheets to be excluded in column A as per the screen snippet. The name of the column header is really irrelevant.
I am not sure if you want to clear the Main data sheet prior to copying the data from the source sheets so I have included a line to do this and you will find it between two asterisk lines so if you don't want to clear the data first then just comment out the line (or delete it).
If you use a different name than "Main data" for the output sheet then edit the VBA code accordingly where I have made the comment. Similarly, if you use a different name for the Exclude list and ensure that both these sheets are included in the Exclude list as above screen snippet.
Note that there is the main sub to run plus a UDF (User Defined Function) in the code. The UDF is used to find the next unused row on the output worksheet.
Feel free to get back to me if any problems.
Sub CopyFromMultiShts()
Dim wsMain As Worksheet
Dim wsExclude As Worksheet
Dim rngColHeaders As Range
Dim ws As Worksheet
Dim lngNextRow As Long
Dim cel As Range
Dim rngToFind As Range
Dim rngDestin As Range
Dim rngToCopy As Range
Set wsMain = Worksheets("Main data") 'Edit "Main data" to your output worksheet name
Set wsExclude = Worksheets("Exclude List") 'Edit "Exclude List" to worksheet with list of worksheets to exclude
With wsMain
'Assign Column Headers of Main data sheet to a range variable
Set rngColHeaders = .Range(.Cells(1, 1), .Cells(1, .Columns.Count).End(xlToLeft))
'**************************************************************************************
.Rows(2 & ":" & .Rows.Count).ClearContents 'Optional to clear existing data first.
'**************************************************************************************
End With
For Each ws In Worksheets 'Loop through worksheets
If WorksheetFunction.CountIf(wsExclude.Columns("A:A"), ws.Name) = 0 Then 'Equal zero then not in exclude list
lngNextRow = LastRowOrCol(True, wsMain.Cells) + 1 'Next blank row in Main data worksheet
With ws
'Assign column headers of source worksheet to a range variable
Set rngColHeaders = .Range(.Cells(1, 1), .Cells(1, .Columns.Count).End(xlToLeft))
For Each cel In rngColHeaders 'Loop through column headers in source worksheet
If WorksheetFunction.CountA(cel.EntireColumn) > 1 Then 'If more than column header data exists
With wsMain 'Start of nested With/End With
'Search for column header in Main data worksheet
Set rngToFind = .Rows(1).Find(What:=cel.Value, _
LookIn:=xlFormulas, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If rngToFind Is Nothing Then GoTo SkipCopy 'If Nothing then column header not found so skip copy
'Next blank row in Main data (lngNextRow from above) and column where column header found
Set rngDestin = .Cells(lngNextRow, rngToFind.Column)
End With 'End nested With/End With
'Assign data from source worksheet to a range variable (From cell below column header to bottom of data)
Set rngToCopy = .Range(cel.Offset(1, 0), .Cells(.Rows.Count, cel.Column).End(xlUp))
'Copy column from source worksheet to Main data worksheet
rngToCopy.Copy Destination:=rngDestin
End If
SkipCopy:
Next cel
End With
End If
Next ws
wsMain.Columns.AutoFit 'Optional code
End Sub
Function LastRowOrCol(bolRowOrCol As Boolean, Optional rng As Range) As Long
'Finds the last used row or column in a worksheet
'First parameter is True for Last Row or False for last Column
'Third parameter is optional
'Must be specified if not ActiveSheet
Dim lngRowCol As Long
Dim rngToFind As Range
If rng Is Nothing Then
Set rng = ActiveSheet.Cells
End If
If bolRowOrCol Then
lngRowCol = xlByRows
Else
lngRowCol = xlByColumns
End If
With rng
Set rngToFind = rng.Find(What:="*", _
LookIn:=xlFormulas, _
LookAt:=xlPart, _
SearchOrder:=lngRowCol, _
SearchDirection:=xlPrevious, _
MatchCase:=False)
End With
If Not rngToFind Is Nothing Then
If bolRowOrCol Then
LastRowOrCol = rngToFind.Row
Else
LastRowOrCol = rngToFind.Column
End If
End If
End Function