Copy data from a Subset of Worksheets in a workbook and pasting to a master worksheet, disregarding the standard mastersheets - excel

Hello to the community and thank you in advance for your assistance. I have created a workbook that has a variable number of worksheets most of which have variable name. There are however, 4 worksheets that will not change and I do not want data copied from them. The code I am attempting is below: If I am way off base, please let me know.
V/R
Doug
Private Sub GroupReport_Click()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim CopyRng As Range
Dim Disreguard(1 To 4) As String
Disreguard(1) = "RDBMergeSheet"
Disreguard(2) = "0 Lists"
Disreguard(3) = "0 MasterCrewSheet"
Disreguard(4) = "00 Overview"
' Delete the summary sheet if it exists.
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
On Error GoTo 0
Application.DisplayAlerts = True
' Add a new summary worksheet.
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "RDBMergeSheet"
' Loop through all worksheets and copy the data to the
' summary worksheet.
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> Disreguard.Worksheets.Name Then
Last = LastRow(DestSh)
Set CopyRng = sh.Rows("21")
CopyRng.Copy
With DestSh.Cells(Last + 1, "A")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
End If
Next

Unfortunately, this line will not work for you:
If sh.Name <> Disreguard.Worksheets.Name Then
The Disreguard variable is an array, but not an object in VBA, so there are no methods you can access with the dot operator. You would have to loop through the array's contents and check each item against the string you're testing.
You can add a function to test it like this:
Private Function toDisreguard(ByRef list() as String, ByRef searchString As String) As Boolean
Dim i As Long
For i = LBound(list) To UBound(list)
If (searchString = list(i)) Then
toDisreguard = True
Exit Function
End If
Next i
toDisreguard = False
End Function
And then pass the array along with the sheet name to test like so:
If (toDisreguard(Disreguard, sh.Name) = False) Then
Also, the LastRow() function is not defined from what you posted. Is this a function you created?
In fact, you could just keep track of the last row yourself since you're rebuilding the "RDBMergeSheet" worksheet each time you run this. You can start by setting Last = 1 and then increment along the way. And one last thing, you should probably test to see if there is any data in row 21 for each sheet so you're not copying a blank row:
' Loop through all worksheets and copy the data to the
' summary worksheet.
Last = 1
For Each sh In ActiveWorkbook.Worksheets
If (toDisreguard(Disreguard, sh.Name) = False) Then
'Last = LastRow(DestSh)
If (Application.WorksheetFunction.CountA(sh.Rows("21")) > 0) Then
Set CopyRng = sh.Rows("21")
CopyRng.Copy
With DestSh.Cells(Last, "A") ' notice i changed this as well
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
Last = Last + 1
End If
End If
Next

Related

Skiping Multiple sheets in a Workbook

I need a code for skipping Multiple worksheets and go to the next sheet in excel
I tried using select case and if array but it won't work
Sub s()
Select Case Sheet
Case Is = "Weekly Spread (%),Weekly spread (Count)Summary,Sheet1,Consolidated_Data"
Case Else
t = 0
Sheet.Select
If t = 1 Then
Range("a1").Select
Range(Selection, Selection.End(xlToRight).End(xlDown)).Copy
Else
Range("a2").Select
Range(Selection, Selection.End(xlToRight).End(xlDown)).Copy
End If
Sheets("LoginData").Select
If t = 1 Then
Range("a1").Select
Selection.PasteSpecial xlPasteValues
Else
Range("A1").Select
Selection.End(xlDown).Offset(1, 0).Select
Selection.PasteSpecial xlPasteValues
End If
End Select
t = t + 1
End Sub
Import Table Values
Option Explicit
Sub ImportData()
Dim Exceptions(): Exceptions = Array("LoginData", "Weekly Spread (%)", _
"Weekly spread (Count)Summary", "Sheet1", "Consolidated_Data")
Dim wb As Workbook: Set wb = ThisWorkbook
Dim dws As Worksheet: Set dws = wb.Sheets("LoginData")
'dws.Cells.Clear ' clear previous data
Dim dCell As Range: Set dCell = dws.Range("A1") ' first
Dim sws As Worksheet, srg As Range, IsFirstFound As Boolean
For Each sws In wb.Worksheets ' '.Sheets' would include charts!
If IsError(Application.Match(sws.Name, Exceptions, 0)) Then ' not found
If IsFirstFound Then ' it's not the first; exclude headers
With sws.Range("A1").CurrentRegion
Set srg = .Resize(.Rows.Count - 1).Offset(1)
End With
Else ' it's the first; include headers
Set srg = sws.Range("A1").CurrentRegion
IsFirstFound = True
End If
dCell.Resize(srg.Rows.Count, srg.Columns.Count).Value = srg.Value
Set dCell = dCell.Offset(srg.Rows.Count) ' next
'Else ' found; it's one from the exceptions array; do nothing
End If
Next sws
MsgBox "Data imported into """ & dws.Name & """.", vbInformation
End Sub
Some Thoughts on Your Code
Sub s()
' Next time show us the variable declarations and the For Each...Next loop.
Dim Sheet As Worksheet
Dim t As Long ' it is already 0; my code uses a boolean 'IsFirstFound'.
For Each Sheet In ThisWorkbook.Worksheets
Select Case Sheet
' This was a major mistake. Also, 'LoginData' had to be included.
' Also, keep in mind that this is case sensitive i.e. e.g. 'sheet1'
' will not be excluded. In my code 'Application.Match' is used
' on an array of the names which is not case sensitive.
Case "LoginData", "Weekly Spread (%)", _
"Weekly spread (Count)Summary", "Sheet1", "Consolidated_Data"
Case Else
' No need to use 'Select'. Use the 'With' statement instead.
' Best use variables to reference the workbook, worksheets
' and ranges. See 'wb', 'sws', 'dws', 'srg' and 'dCell' in my code.
' You needed to switch 'A1' and 'A2', or use 'If t = 0 Then'.
' It is very risky to use 'xlToRight' and 'xlDown' with 'A2' i.e.
' if a single cell in row 2 is empty, the wrong range
' will be referenced. The same goes for 'xlDown' in column 'A'
' while pasting.
' See the use of 'CurrentRegion', 'Resize' and 'Offset' in my code.
' Copying by assignment is faster and doesn't mess with
' the selection like 'PasteSpecial' does.
' The following two blocks of code are highly unreliable.
' You could call it a first step in getting rid of 'Select'.
With Sheet
If t = 0 Then ' first worksheet
.Range(.Range("A1"), .Range("A1").End(xlToRight).End(xlDown)).Copy
Else ' all but the first worksheet
.Range(.Range("A2"), .Range("A2").End(xlToRight).End(xlDown)).Copy
End If
End With
With ThisWorkbook.Sheets("LoginData")
If t = 0 Then ' first worksheet
.Range("A1").PasteSpecial xlPasteValues
Else ' all but the first worksheet
.Range("A1").End(xlDown).Offset(1, 0).PasteSpecial xlPasteValues
End If
End With
End Select
t = 1 ' since 'If T = 0 Then' is used (switches to all but the first)
Next Sheet
' There are too many issues for such a code to be reliable!
' It will work until it doesn't which may be sooner than you expect.
End Sub
Code changed assuming you want to iterate the sheets on the current workbook. I think you need to add LoginData to the list to avoid copying data from the same sheet.
Sub s()
For Each Sheet In ThisWorkbook.Sheets
Select Case Sheet.Name
' I think yo need to add LoginData to this list to avod copying into itself
Case "Weekly Spread (%)", "Weekly spread (Count)Summary", "Sheet1", "Consolidated_Data"
Case Else
t = 0
Sheet.Select
If t = 1 Then 'Why the difference here? I do understand it in the paste but not here
Range("a1").Select
Range(Selection, Selection.End(xlToRight).End(xlDown)).Copy
Else
Range("a2").Select
Range(Selection, Selection.End(xlToRight).End(xlDown)).Copy
End If
Sheets("LoginData").Select
If t = 1 Then
Range("a1").Select
Selection.PasteSpecial xlPasteValues
Else
Range("A1").Select
Selection.End(xlDown).Offset(1, 0).Select
Selection.PasteSpecial xlPasteValues
End If
End Select
t = t + 1
Next Sheet
End Sub

Excel VBA remove blank rows from specific range

I have an excel macro that creates a new sheet called "Compiled", copies over the contents of every sheet in the workbook from A2 onward (so the header isn't copied). This works great, except I often get tons of completely blank rows all over the place.
My objective is to have a macro to find the last row in the Compiled sheet, and delete any fully blank rows.
Here's my current script:
Sub CombineData()
' Delete unneeded sheets
Application.DisplayAlerts = False
Sheets("Instructions").Select
ActiveWindow.SelectedSheets.Delete
Sheets("TM Contacts").Select
ActiveWindow.SelectedSheets.Delete
' Add new sheet called Compiled
Sheets.Add After:=ActiveSheet
Sheets("Sheet1").Select
Sheets("Sheet1").Name = "Compiled"
Sheets("Lastname, First Name").Select
Range("Table_1[#Headers]").Select
Selection.Copy
Sheets("Compiled").Select
Range("A1").Select
ActiveSheet.Paste
Range("A2").Select
' Copy all sheet contents onto one
Dim lastRowSource As Long, lastRowDest As Long, i As Long
For i = 1 To Sheets.Count
If Not Sheets(i).Name = "Compiled" Then
lastRowSource = Sheets(i).Cells(Sheets(i).Rows.Count, "A").End(xlUp).Row
lastRowDest = Sheets("Compiled").Cells(Sheets("Compiled").Rows.Count, "A").End(xlUp).Row
With Sheets(i)
.Range(.Cells(2, "A"), .Cells(lastRowSource, "AB")).Copy Sheets("Compiled").Range(Sheets("Compiled").Cells(lastRowDest + 1, "A"), Sheets("Compiled").Cells(lastRowDest + 1 + lastRowSource, "AB"))
End With
End If
Next i
' delete blank rows
End Sub
I tried this code from an older question to delete the blank rows, which gave me an "out of range" error:
Dim myWs As Worksheet
Set myWs = ThisWorkbook.Worksheets("Compiled") 'set your sheet name
Dim lastRow As Long
lastRow = myWs.Range("A" & myWs.Rows.Count).End(xlUp).Row 'find last used row
With myWs.Range(myWs.Cells(2, "A"), myWs.Cells(lastRow, "A"))
.Value = .Value 'convert formulas to values whithin the range from with block (column A only)
.SpecialCells(xlCellTypeBlanks).EntireRow.Delete 'delete rows where column A is blank
End With
The error with this code appears to be at "Dim myWs As Worksheet". This is where I get the "out of range" error. I'm trying to point to the compiled worksheet.
If I am not wrong, you want to combine data from different worksheets into one master sheet. But your code is producing lots of empty rows in the "Compiled" sheet. That's why you want to "remove blank rows from specific range".
What I understand from your code:
you want to:
delete sheets named "Instructions" and "TM Contacts"
add a new sheet "Compiled"
copy header from the table "Table_1" in sheet "<Last Name, First Name>" and paste it as header for sheet "Compiled"
copy data "A2" to "AB & last row" from all sheets to sheet "Compiled", starting from "A2"
Please check if this works:
Here I have tried to avoid .select
Option Explicit
Sub CombineData()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim lastRowDest As Long
Dim lastRowSource As Long
Dim CopyRng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
'delete sheets named "Instructions" and "TM Contacts". also delete "Compiled", if it exists.
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("Instructions").Delete
ActiveWorkbook.Worksheets("TM Contacts").Delete
ActiveWorkbook.Worksheets("Compiled").Delete
On Error GoTo 0
Application.DisplayAlerts = True
'add a new sheet "Compiled"
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "Compiled"
'copy header from the table "Table_1" in sheet "Last Name, First name" and paste it as header for sheet "Compiled"
'from your code I assume you have a data formatted as a table, "Table_1"
ActiveWorkbook.Worksheets("Last Name, First Name").ListObjects("Table_1").HeaderRowRange.Copy
DestSh.Range("A1").PasteSpecial xlPasteValues
'copy data "A2" to "AB & last row" from all sheets to sheet "Compiled",starting from "A2"
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name Then
With DestSh
lastRowDest = .Range("A" & .Rows.Count).End(xlUp).Row
End With
With sh
lastRowSource = .Range("A" & .Rows.Count).End(xlUp).Row
End With
'if you want to change copy range, change here
Set CopyRng = sh.Range("A2:AB" & lastRowSource)
With CopyRng
DestSh.Cells(lastRowDest + 1, "A").Resize(.Rows.Count, .Columns.Count).Value = .Value
End With
End If
Next
ExitTheSub:
Application.Goto DestSh.Cells(1)
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub

Excel VBA: combine multiple worksheets into one

I use the following code to combine multiple worksheets. The problem is, that this code works with worksheets that have title in the first row and my worksheets do not have. It is possible to select only 3 columns (A, F and G).. I mean the range from the woorksheets? The worksheets have the same structure only the number of lines may be different. Any idea? Thanks!
Sub Combine()
Dim J As Integer
On Error Resume Next
Sheets(1).Select
Worksheets.Add ' add a sheet in first place
Sheets(1).Name = "Combined"
' copy headings
Sheets(2).Activate
Range("A1").EntireRow.Select
Selection.Copy Destination:=Sheets(1).Range("A1")
' work through sheets
For J = 2 To Sheets.Count ' from sheet 2 to last sheet
Sheets(J).Activate ' make the sheet active
Range("A1").Select
Selection.CurrentRegion.Select ' select all cells in this sheets
' select all lines except title
Selection.Offset(1, 0).Resize(Selection.Rows.Count - 1).Select
' copy cells selected in the new sheet on last line
Selection.Copy Destination:=Sheets(1).Range("A65536").End(xlUp)(2)
Next
End Sub
Instead of copying only A, F+G you can delete all columns you don't need from the resulting sheet.
Sub Combine()
Dim jCt As Integer
Dim ws As Worksheets
Dim myRange As Range
Dim lastRow As Long
lastRow = 1
'Delete Worksheet combine if it exists
If sheetExists("Combined") Then
Application.DisplayAlerts = False
Sheets("Combined").Delete
Application.DisplayAlerts = True
MsgBox "Worksheet ""Combined"" deleted!"
End If
Worksheets.Add ' add a sheet in first place
Sheets(1).Name = "Combined"
' work through sheets
For jCt = 2 To Sheets.Count ' from sheet 2 to last sheet
Set myRange = Sheets(jCt).Range(Sheets(jCt).Cells(1, 1), Sheets(jCt).Range("A1").SpecialCells(xlCellTypeLastCell))
Debug.Print Sheets(jCt).Name, myRange.Address
'Put the SheetName on the Sheet "Cominbed"
Sheets("Combined").Range("A1").Offset(lastRow, 0) = Sheets(jCt).Name
With Sheets("Combined").Range("A1").Offset(lastRow, 0).Font
.Bold = True
.Size = 14
End With
'copy the sheets
myRange.Copy Destination:=Sheets("Combined").Range("A1").Offset(lastRow + 2, 0)
lastRow = lastRow + myRange.Rows.Count + 3
Next
End Sub
Function sheetExists(sheetToFind As String) As Boolean
sheetExists = False
For Each Sheet In Worksheets
If sheetToFind = Sheet.Name Then
sheetExists = True
Exit Function
End If
Next Sheet
End Function

If Condition to create sheets only when Auto filter has data

I have written a code which does the below steps.
1) Loops through a list of products
2) Auto filters the data with each product.
3) Copies and pastes data on to separate worksheets and names it with that product name.
4) Inserts a line at every change in schedule
The only thing I couldn't do it here is to limit separate worksheet creation only for the products available in the source data when auto filtered.
I tried to do this by adding an if condition to add worksheets by product name only if auto filter shows any data but for some reason it is not working.
I would appreciate any help in fixing this problem and clean my code to make it look better and work faster.
Sub runreport()
Dim rRange As Range
Dim Rng As Range
' Open the Source File
Filename = Application.GetOpenFilename()
Workbooks.Open Filename
'Loops through each product type range from the macro spreadsheet.
For Each producttype In ThisWorkbook.Sheets("Schedule").Range("Product")
' Filters the sheet with a product code that matches and copy's the active sheet selection
Workbooks("Source.xlsx").Sheets("Sheet1").Range("A1:G1").AutoFilter Field:=4, Criteria1:=producttype
Sheets("Sheet1").Select
Sheets("Sheet1").Select
Range("A2").Select
Range(Selection, Selection.End(xlDown)).Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
'Adds a new workbook
ActiveWorkbook.Sheets.Add After:=ActiveWorkbook.Sheets(Sheets.Count)
'Names the worksheet by Prod type descreption doing a vlookup from the spreadsheet
ActiveSheet.Name = Application.VLookup(producttype, ThisWorkbook.Sheets("Sheet2").Range("A:B"), 2, False)
'This will paste the filtered data from Source Data to the new sheet that is added
Range("a2").Select
ActiveSheet.Paste
ns = ActiveSheet.Name
'Copeis the headers to all the new sheets
Sheets("Sheet1").Select
Range("A1:BC1").Select
Selection.Copy
Sheets(ns).Activate
Range("a1").Select
ActiveSheet.Paste
Columns.AutoFit
' Inserts a blank row for everychange in ID
myRow = 3
Do Until Cells(myRow, 3) = ""
If Cells(myRow, 3) = Cells(myRow - 1, 3) Then
myRow = myRow + 1
Else
Cells(myRow, 1).EntireRow.Insert
myRow = myRow + 2
End If
Loop
Next producttype
End Sub
Try this...
Sub runreport()
Dim rRange As Range
Dim Rng As Range
Dim FiltRows As Integer
' Open the Source File
Filename = Application.GetOpenFilename()
Workbooks.Open Filename
'Loops through each product type range from the macro spreadsheet.
For Each producttype In ThisWorkbook.Sheets("Schedule").Range("Product")
' Filters the sheet with a product code that matches and copy's the active sheet selection
Workbooks("Source.xlsx").Sheets("Sheet1").Range("A1:G1").AutoFilter Field:=4, Criteria1:=producttype
With Workbooks("Source.xlsx").Sheets("Sheet1")
FiltRows = .AutoFilter.Range.Rows.SpecialCells(xlCellTypeVisible).Count / .AutoFilter.Range.Columns.Count
End With
If FiltRows > 1 Then 'There will always be a header row which is why it needs to be greater than one.
Sheets("Sheet1").Select
Sheets("Sheet1").Select
Range("A2").Select
Range(Selection, Selection.End(xlDown)).Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
'Adds a new workbook
ActiveWorkbook.Sheets.Add After:=ActiveWorkbook.Sheets(Sheets.Count)
'Names the worksheet by Prod type descreption doing a vlookup from the spreadsheet
ActiveSheet.Name = Application.VLookup(producttype, ThisWorkbook.Sheets("Sheet2").Range("A:B"), 2, False)
'This will paste the filtered data from Source Data to the new sheet that is added
Range("a2").Select
ActiveSheet.Paste
ns = ActiveSheet.Name
'Copeis the headers to all the new sheets
Sheets("Sheet1").Select
Range("A1:BC1").Select
Selection.Copy
Sheets(ns).Activate
Range("a1").Select
ActiveSheet.Paste
Columns.AutoFit
' Inserts a blank row for everychange in ID
myRow = 3
Do Until Cells(myRow, 3) = ""
If Cells(myRow, 3) = Cells(myRow - 1, 3) Then
myRow = myRow + 1
Else
Cells(myRow, 1).EntireRow.Insert
myRow = myRow + 2
End If
Loop
End If
Next producttype
End Sub
I would recommend you define more variables than you have it keeps the code cleaner and easier to read as well as eliminates easy errors.
I also recommend always to utilize "option explicit" at the top of every code. It forces defining all variables (when you don't define a variable the program will do it for you (assuming you haven't used option explicit), but excel doesn't always get it correct. Also option explicit helps you avoid typos in variables.
Also as a general rule you rarely if ever have to .select anything to do what you need to with vba.
Below is an example of a cleaned up and shortened code which utilized variable definition and instantiation.
Sub runreport()
Dim wb As Workbook
Dim wsSched As Worksheet
Dim wsNew As Worksheet
Dim wbSource As Workbook
Dim wsSource As Worksheet
Dim rRange As Range
Dim producttype As Range
Dim Filename As String
Dim FiltRows As Integer
Dim myRow As Integer
'instantiate Variables
Set wb = ThisWorkbook
Set wsSched = wb.Worksheets("Schedule")
' Open the Source File
Filename = Application.GetOpenFilename()
Set wbSource = Workbooks.Open(Filename)
Set wsSource = wbSource.Worksheets("Sheet1")
'Loops through each product type range from the macro spreadsheet.
For Each producttype In wsSched.Range("Product")
' Filters the sheet with a product code that matches and copy's the active sheet selection
With wsSource
.AutoFilterMode = False
.Range("A1:G1").AutoFilter Field:=4, Criteria1:=producttype
FiltRows = .AutoFilter.Range.Rows.SpecialCells(xlCellTypeVisible).Count / .AutoFilter.Range.Columns.Count
If FiltRows > 1 Then 'There will always be a header row which is why it needs to be greater than one.
'Add new workbook
Set wsNew = wb.Sheets.Add(After:=ActiveWorkbook.Sheets(Sheets.Count))
'Copy filtered data including header
.AutoFilter.Range.SpecialCells(xlCellTypeVisible).Copy
'Paste filterd data and header
wsNew.Range("A1").PasteSpecial
Application.CutCopyMode = False
wsNew.Columns.AutoFit
'Rename new worksheet
wsNew.Name = WorksheetFunction.VLookup(producttype, wb.Worksheets("Sheet2").Range("A:B"), 2, False)
' Inserts a blank row for everychange in ID
myRow = 3
Do Until Cells(myRow, 3) = ""
If Cells(myRow, 3) = Cells(myRow - 1, 3) Then
myRow = myRow + 1
Else
Cells(myRow, 1).EntireRow.Insert
myRow = myRow + 2
End If
Loop
End If
End With
Next producttype
End Sub
First, you can check this answer for ways to optimize your vba code
As for your code in its current form, it would be easiest if you select the entire range of your product code data first. Then you can check this range after your filter and determine if all the rows are hidden. See a sample of the code below
Dim productData as Range
Set productData = Range(Range("A2"), Range("A2").End(xlDown).End(xlToRight))
' Filters the sheet with a product code that matches and copy's the active sheet selection
Workbooks("Source.xlsx").Sheets("Sheet1").Range("A1:G1").AutoFilter _
Field:=4, Criteria1:=producttype
' The error check will skip the creation of a new sheet if the copy failed (i.e. returns a non-zero error number)
On Error Resume Next
' Copies only the visible cells
productData.SpecialCells(xlCellTypeVisible).Copy
If Err.number = 0 then
'Adds a new workbook
ActiveWorkbook.Sheets.Add After:=ActiveWorkbook.Sheets(Sheets.Count)
ActiveSheet.Name = Application.VLookup(producttype, _
ThisWorkbook.Sheets("Sheet2").Range("A:B"), 2, False)
Range("a2").Select
ActiveSheet.Paste
End If
While you can Range.Offset one row and check if the Range.SpecialCells method with xlCellTypeVisible is Not Nothing, I prefer to use the worksheet's SUBTOTAL function. The SUBTOTAL function discards hidden or filtered rows from its operations so a simple COUNTA (SUBTOTAL subfunction 103) of the cells below the header will tell you if there is anything available.
Sub runreport()
Dim rRange As Range, rHDR As Range, rVAL As Range, wsn As String
Dim fn As String, owb As Workbook, twb As Workbook
Dim i As Long, p As Long, pTYPEs As Variant
pTYPEs = ThisWorkbook.Sheets("Schedule").Range("Product").Value2
Set twb = ThisWorkbook
' Open the Source File
fn = Application.GetOpenFilename()
Set owb = Workbooks.Open(fn)
With owb
'is this Workbooks("Source.xlsx")?
End With
With Workbooks("Source.xlsx").Worksheets("Sheet1")
With .Cells(1, 1).CurrentRegion
'store the header in case it is needed for a new worksheet
Set rHDR = .Rows(1).Cells
'reset the the filtered cells
Set rVAL = Nothing
For p = LBound(pTYPEs) To UBound(pTYPEs)
.AutoFilter Field:=4, Criteria1:=pTYPEs(p)
With .Resize(.Rows.Count - 1, 7).Offset(1, 0) '<~~resize to A:G and move one down off the header row
If CBool(Application.Subtotal(103, .Cells)) Then
'there are visible cells; do stuff here
Set rVAL = .Cells
wsn = Application.VLookup(pTYPEs(p), twb.Worksheets("Sheet2").Range("A:B"), 2, False)
'if the wsn worksheet doesn't exist, go make one and come back
On Error GoTo bm_New_Worksheet
With Worksheets(wsn)
On Error GoTo bm_Safe_Exit
rVAL.Copy Destination:=.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
'when inserting rows, always work from the bottom to the top
For i = .Cells(Rows.Count, 3).End(xlUp).Row To 3 Step -1
If .Cells(i, 3).Value2 <> .Cells(i - 1, 3).Value2 Then
.Rows(i).Insert
End If
Next i
'autofit the columns
For i = .Columns.Count To 1 Step -1
.Columns(i).AutoFit
Next i
End With
End If
End With
Next p
End With
End With
GoTo bm_Safe_Exit
bm_New_Worksheet:
On Error GoTo 0
With Worksheets.Add(after:=Sheets(Sheets.Count))
.Name = wsn
rHDR.Copy Destination:=.Cells(1, 1)
End With
Resume
bm_Safe_Exit:
End Sub
When a worksheet that is referenced by the wsn string does not exist, the On Error GoTo bm_New_Worksheet runs off and creates one. The Resume brings the code processing right back to the place it errored out.
One caution when using this method is to ensure that you have unique, legal worksheet names returned by your VLOOKUP function.

run macro on AutoFilter and show data in new sheet

Actually what i want to do , i have following data With Auto Filtering ,
-> I want to create new sheet for each unique Name selected from filtering .i.e. if John and Alex are selected then 2 new sheets should be created one for John and second for Alex , and each of them show own data (Name + No + R). When Next time if master sheet get updated then news data should be appended when i run macro. i'm using following code but its not working 100%.
Sub mycar()
x = 2
Do While Cells(x, 1) <> ""
If Cells(x, 1) = "John" Then
Worksheets("Sheet1").Rows(x).Copy
Worksheets("Sheet2").Activate
eRow = Worksheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
ActiveSheet.Paste Destination:=Worksheets("Sheet2").Rows(eRow)
End If
Worksheets("Sheet1").Activate
x = x + 1
Loop
End Sub
-> Here it copy only single data Written in the quotes.
-> Second time if i run this code , it is appending same data again with new data.
Help me to avoid this mistakes.
Thank you.
As discussed there is other possibility to set filter parameters in Array in procedure. The code would look like this one:
Sub Solution()
Dim shData As Worksheet
Set shData = Sheets("Arkusz1") 'or other reference to data sheet
Dim shNew As Worksheet
shData.Activate
'get unique values based on Excel features
Range("a1").AutoFilter
Dim myArr As Variant
myArr = Array("John", "max")
Range("a1").AutoFilter
Dim i As Long
For i = 0 To UBound(myArr)
shData.Range("$A$1").AutoFilter Field:=1, Criteria1:=myArr(i), _
Operator:=xlAnd
On Error Resume Next
Sheets(myArr(i)).Range("A1").CurrentRegion.ClearContents
If Err.Number = 0 Then
Range("A1").CurrentRegion.Copy Sheets(myArr(i)).Range("A1")
Else
Set shNew = Sheets.Add(After:=Sheets(Sheets.Count))
shData.Range("A1").CurrentRegion.Copy shNew.Range("A1")
shNew.Name = myArr(i)
Err.Clear
End If
Next i
'removing filter in master sheet
shData.Range("a1").AutoFilter
End Sub
Substitute Worksheets("Sheet1").Rows(x).Copy by Worksheets("Sheet1").Rows(x).EntireRow.Copy
And clear the destination worksheet before adding information.
I do quite similar exercise quite often. Therefore I provide full possible solution with some comments inside the code. It works for all unique values in column A and creates (if not exists) sheet with appropriate name equals to filter parameters.
Sub Solution()
Dim shData As Worksheet
Set shData = Sheets("Arkusz1") 'or other reference to data sheet
Dim shNew As Worksheet
'get unique values based on Excel features
'i guess some will not like it but I do :)
Range("a1").AutoFilter
Range("A1").CurrentRegion.Columns(1).Copy Range("ww1")
Range("ww1").CurrentRegion.RemoveDuplicates Columns:=1, Header:=xlYes
'be sure that range where you copy (like ww1) is empty range around
Dim myArr As Variant
myArr = Range(Range("ww2"), Range("ww2").End(xlDown))
Range("ww1").CurrentRegion.ClearContents 'some cleaning
Range("a1").AutoFilter '
Dim i As Long
For i = 1 To UBound(myArr, 1)
ActiveSheet.Range("$A$1").AutoFilter Field:=1, Criteria1:=myArr(i, 1), _
Operator:=xlAnd
On Error Resume Next
'this is for two reason- to check if appropriate sheet exists, if so to clean top area
'if you need to append you would comment this line
Sheets(myArr(i, 1)).Range("A1").CurrentRegion.ClearContents
If Err.Number = 0 Then
'if you need to append only you would need to set range-to-copy a bit different
Range("A1").CurrentRegion.Copy Sheets(myArr(i, 1)).Range("A1")
Else
Set shNew = Sheets.Add(After:=Sheets(Sheets.Count))
shData.Range("A1").CurrentRegion.Copy shNew.Range("A1")
shNew.Name = myArr(i, 1)
Err.Clear
End If
Next i
End Sub
This could not fully meet your requirements but could be a complete solution to improve accordingly.
Heading ##Below code is as per your requirement. Modify it based upon your requirement.
Private Sub Worksheet_Calculate()
Dim x As Integer
Dim rnge As Integer
x = Range(Selection, Selection.End(xlDown)).Count
rnge = ActiveSheet.UsedRange.SpecialCells(xlCellTypeVisible).Rows.Count
If Range("E1").Value > rnge Then
Range("A1").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Sheets(2).Select
ActiveSheet.Paste
End If
End Sub

Resources