I have an excel workbook that has invoice data for every month with an identical layout. I was wondering if there is a macro that can copy the data from each sheet and paste it all one after the other.
So the first sheet is P1, then P2, P3 etc until P12. I want a macro that will paste P1 data onto a new sheet, then P2 data right underneath it, then P3 etc until the end.
I imagine this would be some sort of For loop, but I'm not sure what the code would look like (I'm very new to vba)
Thank you in advance!!!
How about this option?
Sub CopyDataWithoutHeaders()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim shLast As Long
Dim CopyRng As Range
Dim StartRow As Long
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
'Delete the sheet "RDBMergeSheet" if it exist
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
On Error GoTo 0
Application.DisplayAlerts = True
'Add a worksheet with the name "RDBMergeSheet"
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "RDBMergeSheet"
'Fill in the start row
StartRow = 2
'loop through all worksheets and copy the data to the DestSh
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name Then
'Find the last row with data on the DestSh and sh
Last = LastRow(DestSh)
shLast = LastRow(sh)
'If sh is not empty and if the last row >= StartRow copy the CopyRng
If shLast > 0 And shLast >= StartRow Then
'Set the range that you want to copy
Set CopyRng = sh.Range(sh.Rows(StartRow), sh.Rows(shLast))
'Test if there enough rows in the DestSh to copy all the data
If Last + CopyRng.Rows.Count > DestSh.Rows.Count Then
MsgBox "There are not enough rows in the Destsh"
GoTo ExitTheSub
End If
'This example copies values/formats, if you only want to copy the
'values or want to copy everything look below example 1 on this page
CopyRng.Copy
With DestSh.Cells(Last + 1, "A")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
End If
End If
Next
ExitTheSub:
Application.Goto DestSh.Cells(1)
'AutoFit the column width in the DestSh sheet
DestSh.Columns.AutoFit
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
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
Function LastCol(sh As Worksheet)
On Error Resume Next
LastCol = 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
https://www.rondebruin.nl/win/s3/win002.htm
Because details are very limited in order to get an idea of the sheets' structure i try to create general code which with some modifications will satisfy your needs.
Option Explicit
Sub test()
Dim wsTest As Worksheet, ws As Worksheet
Dim LRW As Long, LRF As Long, LCW As Long
'Here we create a separate sheet namded wsFull to paste the data in it.
Set wsTest = Nothing
On Error Resume Next
Set wsTest = ActiveWorkbook.Worksheets("wsFull")
On Error GoTo 0
If wsTest Is Nothing Then
Worksheets.Add.Name = "wsFull"
End If
Set wsTest = ActiveWorkbook.Worksheets("wsFull")
'Here we loop all sheets except the new sheet named wsFull
For Each ws In ActiveWorkbook.Worksheets
If ws.Name <> "wsFull" Then
With ws
'Here we find last column (using first row) & last row (using Column A) for each sheet we loop
LRW = .Cells(.Rows.Count, "A").End(xlUp).Row
LCW = .Cells(1, .Columns.Count).End(xlToLeft).Column
End With
'Here we find the last row of wsFull in order to find where we will paste the data in.
LRF = wsTest.Cells(wsTest.Rows.Count, "A").End(xlUp).Row
'We paste the data in column A
If LRF = 1 And wsTest.Range("A1").Value = "" Then
ws.Range(ws.Cells(1, 1), ws.Cells(LRW, LCW)).Copy wsTest.Range("A1")
Else
ws.Range(ws.Cells(1, 1), ws.Cells(LRW, LCW)).Copy wsTest.Range("A" & LRF + 1)
End If
End If
Next ws
End Sub
Related
I have a spreadsheet with 20+ worksheets listing servers. I am trying to format each sheet to pull only the first four columns of data, while preserving the original data. I am inserting 6 columns on the left, creating column headings, copying the first four rows of data (with starting name of "SERV-"), then putting the name of the worksheet in the 5th column. I got the code to work fine if ran in one sheet. I am trying to put it in a loop, but it isn't working. It is inserting the columns and headers in the first worksheet only.
Once I have this loop working, I want to create a summary tab where it pulls the data from these first five rows of each sheet into the summary tab. This should be easy, but I haven't gotten to that point in the code yet.
This is the code I have so far:
'PhaseOne of test code
Sub PhaseOne()
Dim ws As Worksheet
Dim lngRow As Long
Dim lngCount As Long
lngRow = 8
For Each ws In Worksheets
'(2) Remove blank rows (WORKS)
Dim x As Long
With ws
For x = .Cells.SpecialCells(xlCellTypeLastCell).Row To 1 Step -1
If WorksheetFunction.CountA(.Rows(x)) = 0 Then
ws.Rows(x).Delete
End If
Next
End With
'(3) Insert 5 columns (WORKS)
Columns("A:F").Insert Shift:=xlToRight
'(4) Label columns (WORKS)
Range("$A$1").Value = "ServLabel"
Range("$B$1").Value = "Primary IP"
Range("$C$1").Value = "DC"
Range("$D$1").Value = "Service ID"
Range("$E$1").Value = "Sheet"
'(5) Find and Copy Range (WORKS)
Dim lastRow As Long
With ws
lastRow = .Cells(.Rows.Count, "J").End(xlUp).Row
End With
Dim rFound As Range
On Error Resume Next
Set rFound = Cells.Find(What:="SERV-", _
After:=Cells(Rows.Count, Columns.Count), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
On Error GoTo 0
If rFound Is Nothing Then
Else
rFound.Select
Selection.Resize(lastRow, numcolumns + 4).Select
Selection.Copy
Range("A2").Select
ws.Paste
End If
'(8) Enter active sheet name in Column E (WORKS)
If ws.Range("A2") = "" Then
Else
Dim lastRow2 As Long
With ws
lastRow2 = .Cells(.Rows.Count, "d").End(xlUp).Row
End With
Range("E2").Select
Selection.Resize(lastRow2 - 1).Select
Selection = ws.Name
End If
Next ws
End Sub
Unless you have some other reason it's probably easier to just scan the sheets and copy the data to the summary.
Option Explicit
Sub summary()
Const SUM_SHEET = "Summary" ' name of smmary sheet
Const PREFIX = "SERV-*"
Dim wb As Workbook, ws As Worksheet, wsSum As Worksheet
Dim iRow As Long, iSumRow As Long
Dim iStartrow As Long, iLastRow As Long, rng As Range, cell As Range
Set wb = ActiveWorkbook
Set wsSum = wb.Sheets(SUM_SHEET)
wsSum.Range("A1:E1") = Array("ServLabel", "Primary IP", "DC", "Service ID", "Sheet")
iSumRow = 1
For Each ws In wb.Sheets
If ws.Name <> SUM_SHEET Then
' find column SERV-
On Error Resume Next
Set rng = ws.Cells.Find(PREFIX)
On Error GoTo 0
' set scan start/end row
If rng Is Nothing Then
MsgBox "Can't find " & PREFIX & " on " & ws.Name, vbCritical
GoTo SkipSheet
Else
iLastRow = ws.Cells(Rows.Count, rng.Column).End(xlUp).Row
iStartrow = rng.Row + 1
End If
Debug.Print ws.Name, "Col=", rng.Column, "iStartRow=", iStartrow, "iLastRow=", iLastRow
' scan the sheet and write to summary
For iRow = iStartrow To iLastRow
Set cell = ws.Cells(iRow, rng.Column)
' skip blank line
If Len(cell) > 0 Then
iSumRow = iSumRow + 1
cell.Resize(1, 4).Copy wsSum.Cells(iSumRow, 1)
wsSum.Cells(iSumRow, 5) = ws.Name
End If
Next
End If
SkipSheet:
Next
MsgBox iSumRow - 1 & " rows copied to " & wsSum.Name, vbInformation
End Sub
I have three sheets (Sheet1,sheet2 and sheet5)Need to copy from sheet1 column "A","B","E"paste to "Sheet5 "c","G","H" and copy from sheet2 column "J","K", "N" paste to " Sheet5 "c","G","H" (should not overwrite) and Sheet5 i have first three rows are my headers under this it should paste Sheet5 column "G" which has data from sheet1 and sheet2:Need to seperate using autofilter for the specific text "JOhn","Alex","france" only.Separate sheet name should be "JOhn","Alex","france".Need your help on the code:I have tried on below code which is not working for my requirement and am not able to edit because of more conditions( I got from google ) Sub copypaste() Dim lastrow As Integer, erow As Integer, sheet1 As Worksheet, sheet2 As Worksheet Set sheet1 = Worksheets("Sheet1") Set sheet2 = Worksheets("Sheet2") lastrow = sheet1.Cells(Rows.Count, 1).End(xlUp).Row For i = 2 To lastrow erow = sheet2.Cells(Rows.Count, 2).End(xlUp).Offset(1, 0).Row sheet2.Cells(erow, 2) = sheet1.Cells(i, 3) sheet2.Cells(erow, 3) = sheet1.Cells(i, 6) sheet2.Cells(erow, 4) = sheet1.Cells(i, 9) Next i End Sub
Sub CopyDataWithoutHeaders()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim shLast As Long
Dim CopyRng As Range
Dim StartRow As Long
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
'Delete the sheet "RDBMergeSheet" if it exist
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
On Error GoTo 0
Application.DisplayAlerts = True
'Add a worksheet with the name "RDBMergeSheet"
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "RDBMergeSheet"
'Fill in the start row
StartRow = 2
'loop through all worksheets and copy the data to the DestSh
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name Then
'Find the last row with data on the DestSh and sh
Last = LastRow(DestSh)
shLast = LastRow(sh)
'If sh is not empty and if the last row >= StartRow copy the CopyRng
If shLast > 0 And shLast >= StartRow Then
'Set the range that you want to copy
Set CopyRng = sh.Range(sh.Rows(StartRow), sh.Rows(shLast))
'Test if there enough rows in the DestSh to copy all the data
If Last + CopyRng.Rows.Count > DestSh.Rows.Count Then
MsgBox "There are not enough rows in the Destsh"
GoTo ExitTheSub
End If
'This example copies values/formats, if you only want to copy the
'values or want to copy everything look below example 1 on this page
CopyRng.Copy
With DestSh.Cells(Last + 1, "A")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
End If
End If
Next
ExitTheSub:
Application.Goto DestSh.Cells(1)
'AutoFit the column width in the DestSh sheet
DestSh.Columns.AutoFit
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
See the link below for more details.
https://www.rondebruin.nl/win/s3/win002.htm
I want to copy all the rows and columns in multiple worksheets in a one workbook to a single worksheet in a different workbook. In addition, I just want to copy the header once, even though it is in all of the worksheets I'll copy.
I can open the workbook containing all of the worksheets I want to copy to my destination worksheet/workbook however, I don't know how to copy the header only once and often get a Paste Special error.
Sub Raw_Report_Import()
'Define variables'
Dim ws As Worksheet
Dim wsDest As Worksheet
'Set target destination'
Set wsDest = Sheets("Touchdown")
'For loop to copy all data except headers'
For Each ws In ActiveWorkbook.Sheets
'Ensure worksheet name and destination tab do not have same name'
If ws.Name <> wsDest.Name Then
ws.Range("A2", ws.Range("A2").End(xlToRight).End(xlDown)).Copy
wsDest.Cells(Rows.Count, "A").End(xlUp).Offset(1).PasteSpecial xlPasteValues
End If
Next ws
End Sub
Expected: All of the target worksheets from second workbook are copied and pasted to destination worksheet "Touchdown" in first workbook and the header is copied only once.
Actual: Some values are paste but the formatting is wrong from what they were and it is not lining up correctly.
There are a number of things wrong with your code. Please find below code (not tested). Please note the differences so you can improve.
Note, when setting the destination worksheet, I would include the workbook object (if in a different workbook). This will prevent errors from occurring. Also note that this code should be run in the OLD workbook. Additionally, I assume your headers are in Row 1 in each sheet, as such I have included headerCnt to take this into consideration and only copy the headers once.
Option Explicit
Sub Raw_Report_Import()
Dim ws As Worksheet
Dim wsDest As Worksheet
Dim lCol As Long, lRow As Long, lRowTarget As Long
Dim headerCnt As Long
'i would include the workbook object here
Set wsDest = Workbooks("NewWorkbook.xlsx").Sheets("Touchdown")
For Each ws In ThisWorkbook.Worksheets
'this loops through ALL other sheets that do not have touch down name
If ws.Name <> wsDest.Name Then
'need to include counter to not include the header
'establish the last row & column to copy
lCol = ws.Cells(2, ws.Columns.Count).End(xlToLeft).Column
lRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
'establish the last row in target sheet
lRowTarget = wsDest.Range("A" & wsDest.Rows.Count).End(xlUp).Row + 1
If headerCnt = 0 Then
'copy from Row 1
ws.Range(ws.Cells(1, 1), ws.Cells(lRow, lCol)).Copy
Else
'copy from row 2
ws.Range(ws.Cells(2, 1), ws.Cells(lRow, lCol)).Copy
End If
wsDest.Range("A" & lRowTarget).PasteSpecial xlPasteValues
'clear clipboard
Application.CutCopyMode = False
'header cnt
headerCnt = 1
End If
Next ws
End Sub
Try it like this.
Sub CopyDataWithoutHeaders()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim shLast As Long
Dim CopyRng As Range
Dim StartRow As Long
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
'Delete the sheet "RDBMergeSheet" if it exist
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
On Error GoTo 0
Application.DisplayAlerts = True
'Add a worksheet with the name "RDBMergeSheet"
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "RDBMergeSheet"
'Fill in the start row
StartRow = 2
'loop through all worksheets and copy the data to the DestSh
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name Then
'Find the last row with data on the DestSh and sh
Last = LastRow(DestSh)
shLast = LastRow(sh)
'If sh is not empty and if the last row >= StartRow copy the CopyRng
If shLast > 0 And shLast >= StartRow Then
'Set the range that you want to copy
Set CopyRng = sh.Range(sh.Rows(StartRow), sh.Rows(shLast))
'Test if there enough rows in the DestSh to copy all the data
If Last + CopyRng.Rows.Count > DestSh.Rows.Count Then
MsgBox "There are not enough rows in the Destsh"
GoTo ExitTheSub
End If
'This example copies values/formats, if you only want to copy the
'values or want to copy everything look below example 1 on this page
CopyRng.Copy
With DestSh.Cells(Last + 1, "A")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
End If
End If
Next
ExitTheSub:
Application.Goto DestSh.Cells(1)
'AutoFit the column width in the DestSh sheet
DestSh.Columns.AutoFit
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
All details are here.
https://www.rondebruin.nl/win/s3/win002.htm
I want to consolidate multiple worksheets into one worksheet in the same excel, but i don't want some data after a specific word "Total" in all the worksheets. What should i do to delete the data after the word "Total" and then consolidate all the sheets.
Below code is written to add multiple worksheets.
Sub Consolidate()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim erow As Long, lrowsh As Long, startrow As Long
Dim CopyRng As Range
startrow = 3
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
'Deleting "Consolidate" sheet
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("Consolidate").Delete
On Error GoTo 0
Application.DisplayAlerts = True
'Adding worksheet with the name "Consolidate"
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "Consolidate"
'loop through all worksheets and copy the data to the DestSh
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name Then
'Find the next blank or empty row on the DestSh
erow = DestSh.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Row
'Find the last row with data in the Sheet
lrowsh = sh.Range("A" & Rows.Count).End(xlUp).Row
Set CopyRng = sh.Range(sh.Rows(startrow), sh.Rows(lrowsh))
'copies Values / formats
CopyRng.Copy
With DestSh.Cells(erow, 1)
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
End If
Next
End Sub
Interesting Workbook Consolidation
Change the constants (Const) to fit your needs.
The Code
Sub Consolidate()
' Target
Const cTarget As String = "Consolidate" ' Target Worksheet Name
' Source
Const cFR As Long = 3 ' First Row Number
Const cLRC As Variant = 1 ' Last-Row Column Letter/Column Number
Const cCrit As String = "Total" ' Criteria
Dim wb As Workbook ' Target Workbook
Dim wsT As Worksheet ' Target Worksheet
Dim ws As Worksheet ' Current Source Worksheet
Dim eRow As Long ' Target First Empty Row
Dim lRow As Long ' Source Last Used Row
Dim lCol As Long ' Source Last Used Column
Dim rngCell As Range ' Cell Ranges
Dim rng As Range ' Ranges
' Speed up.
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
' Create a reference to Target Workbook. If the code will NOT be in the
' workbook to be processed, then use its name (preferable) or
' ActiveWorkbook instead of ThisWorkbook.
Set wb = ThisWorkbook
' Note: Instead of the following with block you could use code to clear
' or clear the contents of the Target Worksheet.
With wb
'Delete Target Worksheet.
Application.DisplayAlerts = False
On Error Resume Next
.Worksheets("Consolidate").Delete
On Error GoTo 0
Application.DisplayAlerts = True
'Add Target Worksheet.
Set wsT = .Worksheets.Add(Before:=.Sheets(1)) ' First Tab
wsT.Name = "Consolidate"
End With
' Handle errors.
On Error GoTo ErrorHandler
' Loop through all worksheets.
For Each ws In wb.Worksheets
If ws.Name <> wsT.Name Then
With ws.Cells(cFR, cLRC).Resize(ws.Rows.Count - cFR + 1, _
ws.Columns.Count - cLRC + 1)
' Note: Choose only one of the following two lines.
'Find the first occurrence of Criteria in Current Worksheet.
Set rngCell = .Find(cCrit, .Cells(.Rows.Count, .Columns _
.Count), xlValues, xlWhole, xlByRows, xlNext)
' 'Find the last occurrence of Criteria in Current Worksheet.
' Set rng = .Find(cCrit, , xlValues, xlWhole, xlByRows, _
' xlPrevious)
' Clear the range below the row where Criteria was found.
ws.Rows(rngCell.Row + 1 & ":" & ws.Rows.Count).Clear
' Create a reference to Row Range (of Copy Range).
Set rng = .Cells(1).Resize(rngCell.Row - cFR + 1, _
.Columns.Count - cLRC + 1)
End With
' Create a reference to last cell in last column of Row
' Range (of Copy Range).
Set rngCell = rng.Find("*", , xlFormulas, , _
xlByColumns, xlPrevious)
' Create a reference to Copy Range.
Set rng = rng.Cells(1).Resize(rng.Rows.Count, _
rngCell.Column - cLRC + 1)
'Find the next blank or empty row in Target Worksheet.
eRow = wsT.Cells(wsT.Rows.Count, cLRC).End(xlUp) _
.Offset(1, 0).Row
' Copy Copy Range.
rng.Copy
' In (First Empty Row of) Target Worksheet
With wsT.Cells(eRow, 1)
' First paste the formats to avoid trouble mostly when pasting
' dates or time. Excel might firstly format it differently, and
' when pasting the formats might not revert to desired formats.
.PasteSpecial xlPasteFormats
.PasteSpecial xlPasteValues
Application.CutCopyMode = False
End With
End If
Next
' Go to the top of Target Worksheet.
ActiveSheet.Range("A1").Select
' Inform user of success (Since the code is fast, you might not know if it
' had run at all).
MsgBox "The operation finished successfully.", vbInformation, "Success"
ProcedureExit:
' Speed down.
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
Exit Sub
ErrorHandler:
MsgBox "An unexpected error occurred. Error '" & Err.Number & "': " _
& Err.Description, vbCritical, "Error"
GoTo ProcedureExit
End Sub
Hope someone can assist me with my issue. I want to copy specific columns and rows to another worksheet after the condition is met. my worksheet consist of 43 columns where in I have to copy only 29 columns.
The range for the code example below looks like this
Column A : Header in A1 = Country, A2:A? = Country names
Column B : Header in B1 = Name, B2:B? = Names
Column C : Header in C1 = Gender, C2:C? = F or M
Column D : Header in D1 = Birthday, D2:D? = Dates
This example copy all rows with the same value in the first column of the range to a new worksheet. It will do this for every unique value in this column. The sheets will be named after the Unique value.
Check if the information in these lines in the macro is correct before you run the macro
1: Set filter range on ActiveSheet: A1 is the top left cell of your filter range and the header of the first column, D is the last column in the filter range. You can also add the sheet name to the code like this :
Worksheets("Sheet1").Range("A1:D" & LastRow(Worksheets("Sheet1")))
No need that the sheet is active then when you run the macro when you use this.
Set My_Range = Range("A1:D" & LastRow(ActiveSheet))
2: Set the Filter field:This example filter on the first column in the range (change the field if needed). In this case the range starts in A so Field 1 is column A, 2 = column B, ......
FieldNum = 1
3:Important:This macro call a function named LastRow
You find this function below the macro, copy this function together with the macro in a standard module
Sub Copy_To_Worksheets()
'Note: This macro use the function LastRow
Dim My_Range As Range
Dim FieldNum As Long
Dim CalcMode As Long
Dim ViewMode As Long
Dim ws2 As Worksheet
Dim Lrow As Long
Dim cell As Range
Dim CCount As Long
Dim WSNew As Worksheet
Dim ErrNum As Long
'Set filter range on ActiveSheet: A1 is the top left cell of your filter range
'and the header of the first column, D is the last column in the filter range.
'You can also add the sheet name to the code like this :
'Worksheets("Sheet1").Range("A1:D" & LastRow(Worksheets("Sheet1")))
'No need that the sheet is active then when you run the macro when you use this.
Set My_Range = Range("A1:D" & LastRow(ActiveSheet))
My_Range.Parent.Select
If ActiveWorkbook.ProtectStructure = True Or _
My_Range.Parent.ProtectContents = True Then
MsgBox "Sorry, not working when the workbook or worksheet is protected", _
vbOKOnly, "Copy to new worksheet"
Exit Sub
End If
'This example filters on the first column in the range(change the field if needed)
'In this case the range starts in A so Field:=1 is column A, 2 = column B, ......
FieldNum = 1
'Turn off AutoFilter
My_Range.Parent.AutoFilterMode = False
'Change ScreenUpdating, Calculation, EnableEvents, ....
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
ActiveSheet.DisplayPageBreaks = False
'Add a worksheet to copy the a unique list and add the CriteriaRange
Set ws2 = Worksheets.Add
With ws2
'first we copy the Unique data from the filter field to ws2
My_Range.Columns(FieldNum).AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=.Range("A1"), Unique:=True
'loop through the unique list in ws2 and filter/copy to a new sheet
Lrow = .Cells(Rows.Count, "A").End(xlUp).Row
For Each cell In .Range("A2:A" & Lrow)
'Filter the range
My_Range.AutoFilter Field:=FieldNum, Criteria1:="=" & _
Replace(Replace(Replace(cell.Value, "~", "~~"), "*", "~*"), "?", "~?")
'Check if there are no more then 8192 areas(limit of areas)
CCount = 0
On Error Resume Next
CCount = My_Range.Columns(1).SpecialCells(xlCellTypeVisible) _
.Areas(1).Cells.Count
On Error GoTo 0
If CCount = 0 Then
MsgBox "There are more than 8192 areas for the value : " & cell.Value _
& vbNewLine & "It is not possible to copy the visible data." _
& vbNewLine & "Tip: Sort your data before you use this macro.", _
vbOKOnly, "Split in worksheets"
Else
'Add a new worksheet
Set WSNew = Worksheets.Add(After:=Sheets(Sheets.Count))
On Error Resume Next
WSNew.Name = cell.Value
If Err.Number > 0 Then
ErrNum = ErrNum + 1
WSNew.Name = "Error_" & Format(ErrNum, "0000")
Err.Clear
End If
On Error GoTo 0
'Copy the visible data to the new worksheet
My_Range.SpecialCells(xlCellTypeVisible).Copy
With WSNew.Range("A1")
' Paste:=8 will copy the columnwidth in Excel 2000 and higher
' Remove this line if you use Excel 97
.PasteSpecial Paste:=8
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
.Select
End With
End If
'Show all data in the range
My_Range.AutoFilter Field:=FieldNum
Next cell
'Delete the ws2 sheet
On Error Resume Next
Application.DisplayAlerts = False
.Delete
Application.DisplayAlerts = True
On Error GoTo 0
End With
'Turn off AutoFilter
My_Range.Parent.AutoFilterMode = False
If ErrNum > 0 Then
MsgBox "Rename every WorkSheet name that start with ""Error_"" manually" _
& vbNewLine & "There are characters in the name that are not allowed" _
& vbNewLine & "in a sheet name or the worksheet already exist."
End If
'Restore ScreenUpdating, Calculation, EnableEvents, ....
My_Range.Parent.Select
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Sub
Function LastRow(sh As Worksheet)
On Error Resume Next
LastRow = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
https://www.rondebruin.nl/win/s3/win006_4.htm