I have a spreadsheet named Data Sheet that collects data from other worksheets via formulas and works perfectly. I need a macro that will copy the data from multiple rows so I can paste into a separate workbook.
I have 30 rows of data ranging from A3:EI3 to A32:EI32. This data is collected from 1 to 30 other sheets if they are made visible and data entered. Here is the tricky part: I only want to collect the data from the visible sheets.
Here is an example of the flow I am looking for: Sheet 1 is always visible and never is hidden. Sheet 2, Sheet 3, and Sheet 4 are visible, but Sheet 5 through Sheet 30 are still hidden. Data Sheet has already collected the data from the visible sheets, but the remaining rows (Sheets 5-30) all show 0 in the data cells.
I now want to run a macro that will copy the data (to the clipboard) from Data Sheet Row 3 (represents Sheet 1), Row 4 (represents Sheet 2), etc. and allow me to paste into the next available row in another workbook.
Here is the code that works for a single row of data.
VBA Code:
Sub CopyDataSheet()
'
' CopyDataSheet Macro
'
Application.ScreenUpdating = False
Sheets("Data Sheet").Visible = True
Sheets("Data Sheet").Select
Rows("3:3").Select
Selection.Copy
Rows("1:1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("E1:EF1").Select
Application.CutCopyMode = False
Selection.NumberFormat = "0"
Rows("1:1").Select
Range("B1").Activate
Selection.Copy
Sheets("Sheet 1").Select
Range("a38").Select
Sheets("Data Sheet").Visible = True
Application.ScreenUpdating = True
MsgBox "YOU HAVE CAPTURED ALL ENTERED DATA..." & _
vbCrLf & vbCrLf & "CLICK OK" _
& vbCrLf & vbCrLf & "PASTE INTO NEXT EMPTY LINE OF DATA SHEET", _
vbInformation, ""
End Sub
I'm not 100% sure what it is you are trying to do, but I think I can supply a few code fragments that may help you.
This will cycle through the sheets in an active workbook and allow you to do something based on whether or not the sheet is visible:
j = ActiveWorkbook.Sheets.Count
For i = 1 To j
Select Case Sheets(i).Visible
Case xlSheetVisible
'Do something if the sheet is visible
Case Else
'Do something when the sheet is not visible
End Select
Next i
To get the next available row there are many different ways. One of the easiest is simply this:
next_row = Range("A" &
Rows.Count).End(xlUp).row + 1
This assumes that column A will always have a value in any data rows. If this is not the case you may want to try this:
next_row = ActiveSheet.UsedRange.Rows.Count + 1
Neither is bullet proof, but it should at least give you a start.
Option Explicit
Public Sub CollectData()
Dim wsCrnt As Excel.Worksheet
Dim wsDest As Excel.Worksheet
Dim lRowCrnt As Long
Dim lRowDest As Long
On Error GoTo Err_Hnd
ToggleInterface False
Set wsDest = ThisWorkbook.Worksheets("Data Sheet")
lRowDest = wsDest.UsedRange.Rows.Count + 1&
For Each wsCrnt In ThisWorkbook.Worksheets
If wsCrnt.Visible = xlSheetVisible Then
If Not wsCrnt Is wsDest Then
For lRowCrnt = 1& To 30&
If Excel.WorksheetFunction.CountA(wsCrnt.Rows(lRowCrnt)) Then
wsCrnt.Rows(lRowCrnt).Copy
wsDest.Rows(lRowDest).PasteSpecial xlPasteValues
lRowDest = lRowDest + 1
End If
Next
End If
End If
Next
Exit_Proc:
On Error Resume Next
ToggleInterface True
Exit Sub
Err_Hnd:
MsgBox Err.Description, vbCritical Or vbMsgBoxHelpButton, _
"Error: " & Err.Number, Err.HelpFile, Err.HelpContext
Resume Exit_Proc
End Sub
Private Sub ToggleInterface(ByVal interfaceOn As Boolean)
With Excel.Application
.Cursor = IIf(interfaceOn, xlDefault, xlWait)
.StatusBar = IIf(interfaceOn, False, "Working...")
.EnableEvents = interfaceOn
.Calculation = IIf(interfaceOn, xlCalculationAutomatic, xlCalculationManual)
.ScreenUpdating = interfaceOn
.EnableCancelKey = Abs(interfaceOn)
End With
End Sub
Related
I'm working on a master roster that has personnel assigned to different floors. In the master column for assigned floor, I would like the information to transfer to a separate worksheet dedicated to that floor, eight floors total with there own value ( 1 equals first floor worksheet, 2 equals second floor worksheet, and so on).
Name Contact Number Assigned Floor if assigned to floor five will move all previous information to the 5th floor worksheet.
If what I'm trying to do still sounds unclear let me know, but that's the best way to describe it. Would prefer not to use VBA, but if nothing else will appreciate full code layout.
Good question.
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
1: Criteria in the code (=Netherlands, see the tips below the macro)
2: Filter on ActiveCell value
3: Filter on Range value (D1 in this example)
4: Filter on InputBox value
Sub Copy_With_AutoFilter1()
'Note: This macro use the function LastRow
Dim My_Range As Range
Dim CalcMode As Long
Dim ViewMode As Long
Dim FilterCriteria As String
Dim CCount As Long
Dim WSNew As Worksheet
Dim sheetName As String
Dim rng As Range
'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
'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
'Firstly, remove the AutoFilter
My_Range.Parent.AutoFilterMode = False
'Filter and set the filter field and the filter criteria :
'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, ......
'Use "<>Netherlands" as criteria if you want the opposite
My_Range.AutoFilter Field:=1, Criteria1:="=Netherlands"
'If you want to filter on a cell value you can use this, use "<>" for the opposite
'This example uses the activecell value
'My_Range.AutoFilter Field:=1, Criteria1:="=" & ActiveCell.Value
'This will use the cell value from A2 as criteria
'My_Range.AutoFilter Field:=1, Criteria1:="=" & Range("A2").Value
''If you want to filter on a Inputbox value use this
'FilterCriteria = InputBox("What text do you want to filter on?", _
' "Enter the filter item.")
'My_Range.AutoFilter Field:=1, Criteria1:="=" & FilterCriteria
'Check if there are not more then 8192 areas(limit of areas that Excel can copy)
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:" _
& vbNewLine & "It is not possible to copy the visible data." _
& vbNewLine & "Tip: Sort your data before you use this macro.", _
vbOKOnly, "Copy to worksheet"
Else
'Add a new Worksheet
Set WSNew = Worksheets.Add(After:=Sheets(ActiveSheet.Index))
'Ask for the Worksheet name
sheetName = InputBox("What is the name of the new worksheet?", _
"Name the New Sheet")
On Error Resume Next
WSNew.Name = sheetName
If Err.Number > 0 Then
MsgBox "Change the name of sheet : " & WSNew.Name & _
" manually after the macro is ready. The sheet name" & _
" you fill in already exists or you use characters" & _
" that are not allowed in a sheet name."
Err.Clear
End If
On Error GoTo 0
'Copy/paste the visible data to the new worksheet
My_Range.Parent.AutoFilter.Range.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
' If you want to delete the rows that you copy, also use this
' With My_Range.Parent.AutoFilter.Range
' On Error Resume Next
' Set rng = .Offset(1, 0).Resize(.Rows.Count - 1, .Columns.Count) _
' .SpecialCells(xlCellTypeVisible)
' On Error GoTo 0
' If Not rng Is Nothing Then rng.EntireRow.Delete
' End With
End If
'Close AutoFilter
My_Range.Parent.AutoFilterMode = False
'Restore ScreenUpdating, Calculation, EnableEvents, ....
My_Range.Parent.Select
ActiveWindow.View = ViewMode
If Not WSNew Is Nothing Then WSNew.Select
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
From this link.
https://www.rondebruin.nl/win/s3/win006_1.htm
I'm trying to create a userform in VBA that will search a list in another sheet and display all matching results, is it also possible to have that data displayed by default to then be narrowed down by the search box value?
There are three columns in the list it will search, but if it finds a match, ideally it would display the data from the first and third, the middle column is irrelevant, but needs to stay for other code.
Then you might need to select one of the results to display it in a specific folder in the workbook (column one result in one cell, column two in the cell next to it).
I'm completely new to userforms so a task like this is quite daunting, I'm not even certain how to activate the form from the sheet.
Any feedback is appreciated, I'll comment any useful code I find online.
Accomplished most of what I was after with the following:
Private Sub SearchButton_Click()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
On Error GoTo ErrorHandler
Workbooks("Form1.xlsm").Worksheets("Employees").Visible = True
ActiveWorkbook.Sheets("Employees").Activate
Employee = EmployeeName.Value
lastrow = Range("A" & Rows.Count).End(xlUp).Row
ActiveSheet.Range("$A$2:$C$" & lastrow).AutoFilter Field:=1, Criteria1:= _
"=*" & Employee & "*", Operator:=xlAnd
Workbooks("Form1.xlsm").Worksheets("Temp").Visible = xlSheetVisible
Workbooks("Form1.xlsm").Worksheets("Temp").Range("A1:AFD1000000").ClearContents
'validation to stop the form breaking if a nane is searched that doesnt exist
Range("A1000000").Select
Selection.End(xlUp).Select
If ActiveCell.Value = "KeyID" Then GoTo validationend
'Take the data that has been filtered by employee name and store it in a temp worksheet
Range("A2").Select
Range(Selection, Selection.End(xlDown)).Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
Workbooks("Form1.xlsm").Worksheets("Temp").Activate
Range("A1").Select
ActiveSheet.Paste
'Delete any data that is irrelevant at this stage
Range("D:D").Delete Shift:=xlToLeft
Range("E:E").Delete Shift:=xlToLeft
Range("G:AZ").Delete Shift:=xlToLeft
lastrow = Range("A" & Rows.Count).End(xlUp).Row
Dim rngName As Range
Dim ws As Worksheet
Dim i As Integer
Set ws = Worksheets("Temp")
For i = 1 To ws.Cells(ws.Rows.Count, 1).End(xlUp).Row Step 1
If ws.Cells(i, 1).Value <> vbNullString Then Me.ListBox.AddItem ws.Cells(i, 1).Value
Next i
validationend:
Workbooks("Form1.xlsm").Worksheets("Form").Activate
'Workbooks("Form1.xlsm").Worksheets("Temp").Visible = xlSheetVeryHidden
'Workbooks("Form1.xlsm").Worksheets("Employees").Visible = xlSheetVeryHidden
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.Calculation = xlCalculationAutomatic
Exit Sub
ErrorHandler:
MsgBox ("Error: Name not found. Please check your spelling and try again.")
Workbooks("Form1.xlsm").Worksheets("Form").Activate
'Workbooks("Form1.xlsm").Worksheets("Temp").Visible = xlSheetVeryHidden
'Workbooks("Form1.xlsm").Worksheets("Employees").Visible = xlSheetVeryHidden
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.Calculation = xlCalculationAutomatic
End Sub
Doesn't work perfectly, so if you want more answers, I'll be asking relevant questions soon.
I am currently having an issue getting the data from one sheet to paste special into another sheet, I am trying to consolidate multiple files (same headers, differing number of rows) into one master sheet containing all the rows. At the moment I'm doing that by opening all the files, pulling in the tabs I want, copy and pasting the data, and then deleting the tabs. Yes I am sure there is an easier way, but I'm very new to VBA and am learning on the fly..here's what I have so far:
Sub ConsolidateSheets()
' open each file in folder
Dim Folder As String
Dim Files As String
Folder = "C:\Users\212411103\Documents\Risk Project Tracker\Risk Project Tracker Monthly\Monthly Data"
Files = Dir(Folder & "\*.xls")
Do While Files <> ""
Workbooks.Open Filename:=Folder & "\" & Files
Files = Dir
Loop
' pull in Risk Project Tracker tab from each file to new workbook
Dim wkb As Workbook
Dim sWksName As String
sWksName = "Risk Project Tracker"
For Each wkb In Workbooks
If wkb.Name <> ThisWorkbook.Name Then
wkb.Worksheets(sWksName).Copy _
Before:=ThisWorkbook.Sheets(1)
End If
Next
Set wkb = Nothing
Dim J As Integer
' add new sheet for combined data
On Error Resume Next
Sheets(1).Select
Worksheets.Add
Sheets(1).Name = "New Month"
' paste headers from first two rows into new sheet "New Month"
Sheets(2).Select
Range("A1:AH2").Select
Selection.Copy
Sheets("New Month").Select
Selection.PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
ActiveSheet.Paste
Range("A1").Select
' work through sheets
For J = 2 To Sheets.Count ' from sheet 2 to last sheet
Sheets(J).Activate ' make the sheet active
Rows("1:2").Select
Selection.Delete Shift:=xlUp
Range("A1:AH500").Select
Selection.Copy
Sheets("New Month").Select
Selection.PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
Range("A1").Select
Next
' Delete tabs that are no longer needed i.e. the tabs from the 17 files
' For Each ws in Sheets
' Application.DisplayAlerts=False
' If ws.Name <> "New Month" Then ws.delete
' Next
' Application.DisplayAlerts=True
End Sub
It appears that the primary reason you are specifying the Range .PasteSpecial method is the carry-over of column widths which is done for every tab. Perhaps cycling through A:AH once and setting the column widths should be sufficient.
Sub ConsolidateSheets2()
Dim fldr As String, fn As String, sWksName As String, sNewWksName As String
Dim ws As Worksheet, wkb As Workbook
On Error GoTo bm_Safe_Exit
Application.ScreenUpdating = False
Application.EnableEvents = False
sWksName = "Risk Project Tracker"
fldr = "C:\Users\212411103\Documents\Risk Project Tracker\Risk Project Tracker Monthly\Monthly Data"
fn = Dir(fldr & "\*.xls")
sNewWksName = "New Month"
With ThisWorkbook
Do While fn <> ""
Set wkb = Workbooks.Open(Filename:=fldr & Chr(92) & fn)
If IsObject(wkb.Worksheets(sWksName)) Then
wkb.Worksheets(sWksName).Copy _
Before:=ThisWorkbook.Sheets(1 - CBool(Sheets(1).Name = sNewWksName))
On Error GoTo bm_Need_New_Month_ws
With .Worksheets(sNewWksName)
On Error GoTo bm_Safe_Exit
.Parent.Sheets(2).Range("A3:AH502").Copy _
Destination:=.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
End With
End If
wkb.Close False
fn = Dir
Loop
Application.DisplayAlerts = False
Do While Sheet.Count > 1: Sheets(2).Delete: Loop
End With
GoTo bm_Safe_Exit
bm_Need_New_Month_ws:
If Err.Number = 9 Then
With ThisWorkbook.Worksheets.Add(Before:=ThisWorkbook.Sheets(1))
.Name = sNewWksName
.Move Before:=Sheets(1)
.Parent.Sheets(2).Range("A1:AH2").Copy _
Destination:=.Range("A1")
For c = .Columns("AH:AH").Column To 1 Step -1
.Columns(c).ColumnWidth = _
.Parent.Sheets(2).Columns(c).ColumnWidth
Next c
End With
Resume
End If
bm_Safe_Exit:
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
I have the following VBA code that takes a single row from Sheet "Tabled data", copies the data, then pastes the data into the next available row in Sheet "Running list". However the original row has formulas and I need the values to paste, not the formulas. I've seen numerous ways to do it with Range.PasteSpecial but this code didn't use Range and I'm not sure how to incorporate it.
Note: I modified this code from here: http://msdn.microsoft.com/en-us/library/office/ff837760(v=office.15).aspx. It originally had an IF statement to match content in a cell then paste it in a certain sheet according to the content in the cell. I only had one sheet to copy to and didn't need the IF. I don't really need to find the last row of data to copy either as it will only ever be one row with range of A2:N2. But if I take out the FinalRow section and the For and replace with Range("A2:N2") it doesn't work so I left those in.
Any guidance on how to add in the PasteValues property without making this more complicated? I'm also open to simplification of the For or FinalRow variable such as using Range. I'm only sort of familiar with VBA, having done a few things with it, but usually after much searching and modifying code.
Public Sub CopyData()
Sheets("Tabled data").Select
' Find the last row of data
FinalRow = Cells(Rows.Count, 1).End(xlUp).Row
' Loop through each row
For x = 2 To FinalRow
ThisValue = Cells(x, 1).Value
Cells(x, 1).Resize(1, 14).Copy
Sheets("Running list").Select
NextRow = Cells(Rows.Count, 1).End(xlUp).Row + 1
Cells(NextRow, 1).Select
ActiveSheet.Paste
Sheets("Tabled data").Select
Next x
End Sub
Hopefully we can actually make this more simple.
Public Sub CopyRows()
Sheets("Sheet1").UsedRange.Copy
lastrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
'check if the last cell found is empty
If IsEmpty(ActiveSheet.Cells(lastrow, 1)) = True Then
'if it is empty, then we should fill it
nextrow = lastrow
Else
'if it is not empty, then we should not overwrite it
nextrow = lastrow + 1
End If
ActiveSheet.Cells(nextrow, 1).Select
ActiveSheet.Paste
End Sub
edit: I expanded it a little so that there won't be a blank line at the top
I found a working solution. I recorded a macro to get the paste special in there and added the extra code to find the next empty row:
Sub Save_Results()
' Save_Results Macro
Sheets("Summary").Select 'renamed sheets for clarification, this was 'Tabled data'
'copy the row
Range("Table1[Dataset Name]").Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
' paste values into the next empty row
Sheets("Assessment Results").Select
Range("A2").Select
NextRow = Cells(Rows.Count, 1).End(xlUp).Row + 1
Cells(NextRow, 1).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
' Return to main sheet
Sheets("Data Assessment Tool").Select
End Sub
Just copy the data all at once, no need to do it a row at a time.
Sub CopyData()
With ThisWorkbook.Sheets("Tabled data")
Dim sourceRange As Range
Set sourceRange = .Range(.Cells(2, 1), .Cells(getLastRow(.Range("A1").Parent), 14))
End With
With ThisWorkbook.Sheets("Running list")
Dim pasteRow As Long
Dim pasteRange As Range
pasteRow = getLastRow(.Range("A1").Parent) + 1
Set pasteRange = .Range(.Cells(pasteRow, 1), .Cells(pasteRow + sourceRange.Rows.Count, 14))
End With
pasteRange.Value = sourceRange.Value
End Sub
Function getLastRow(ws As Worksheet, Optional colNum As Long = 1) As Long
getLastRow = ws.Cells(ws.Rows.Count, colNum).End(xlUp).Row
End Function
Private Sub Load_Click()
Call ImportInfo
End Sub
Sub ImportInfo()
Dim FileName As String
Dim WS1 As Worksheet
Dim WS2 As Worksheet
Dim ActiveListWB As Workbook
Dim check As Integer
'Application.ScreenUpdating = False
Set WS2 = ActiveWorkbook.Sheets("KE_RAW")
confirm = MsgBox("Select (.xlsx) Excel file for Data transfer." & vbNewLine & "Please ensure the sheets are named Sort List, Second and Third.", vbOKCancel)
If confirm = 1 Then
FileName = Application.GetOpenFilename(FileFilter:="Excel Files (*.xls*),*.xls*", _
Title:="Select Active List to Import", MultiSelect:=False)
If FileName = "False" Then
MsgBox "Import procedure was canceled"
Exit Sub
Else
Call CleanRaw
Set ActiveListWB = Workbooks.Open(FileName)
End If
Set WS1 = ActiveListWB.Sheets("Sort List")
WS1.UsedRange.Copy 'WS2.Range("A1")
' WS2.Range("A1").Select
WS2.UsedRange.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'WS2.Range ("A1")
ActiveWorkbook.Close False
'Call ClearFormulas
' Call RefreshAllPivotTables
Sheets("Key Entry Data").Select
'Sheets("Raw").Visible = False
'Application.ScreenUpdating = True
MsgBox "Data has been imported to workbook"
Else
MsgBox "Import procedure was canceled"
End If
Application.ScreenUpdating = True
End Sub
Sub CleanRaw()
Sheets("KE_RAW").Visible = True
Sheets("KE_RAW").Activate
ActiveSheet.Cells.Select
Selection.ClearContents
End Sub
Both of these macros are macros I found online and adapted to my use. I am using this code and it works well to separate specific data into new sheets:
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:Z" & Range("A" & Rows.Count).End(xlUp).Row)
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 = 5 'I changed this to 3 for column C
'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
What I need help with is to add a particular set of formulas to the bottom of each sheet that is created from the above macro. The following macro adds the formulas to all the sheets in the workbook. I need it to add the formulas to only the sheets that are created in the above macro. The number of sheets created change every time they are generated, depending on the source data. I was thinking it might be best to merge bottom macro into the top but I have no idea how to go about doing that.
Sub Insert_Formulas()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.Activate
'Start
NxtRw = Cells(Rows.Count, "B").End(xlUp).Row + 1
With Cells(NxtRw, "B")
.Value = "Total Open Cases"
End With
With Cells(NxtRw, "C")
.EntireRow.Insert
.Value = "Total Closed Cases"
End With
'Next Row below
NxtRw = Cells(Rows.Count, "B").End(xlUp).Row + 1
With Cells(NxtRw, "B")
.Formula = "=CountIf(B2:B" & NxtRw - 1 & ", ""Open*"")"
End With
With Cells(NxtRw, "C")
.Formula = "=CountIf(B2:B" & NxtRw - 1 & ", ""Closed*"")"
End With
Next
End Sub
Any help would be greatly appreciated.
Thank you, Ck
I wouldn't combine the 2 macros, simply call the Insert_Formulas macro from the Copy_To_Worksheets macro when it is needed.
To call the macro all you need is this line:
Insert_Formulas
Edit to respond to comment:
Given you don't know how many sheets are being added I have one suggestion you may try.
High level, add text to a cell in each sheet to indicate if it is new or not. When new sheet is created cell should say "new". When not new it should say "existing". Then in the
If you want to give this a try, and let me know what doesn't work I can check back and help update the code.
In the Copy_To_Worksheets macro you'll need to add a line to set all existing sheets to "existing"
In then Copy_To_Worksheets macro add a line so that new sheets get set to "new"
In Insert_Formulas macro, still loop through all sheets, but check to see if the sheet is "new", and if so, run the code to add the formulas.
A cleaner (but slightly more difficult) option would be to define a name on each sheet (use the same name for each and limit the scope to each individual sheet) and use that instead of a cell on each sheet.
If you parametrize the function so that it takes the worksheet which needs the formulas as a parameter
Sub Insert_Formulas_Into_WorkSheet(ws As Worksheet)
ws.Activate
'Start
NxtRw = Cells(Rows.Count, "B").End(xlUp).Row + 1
With Cells(NxtRw, "B")
.Value = "Total Open Cases"
End With
With Cells(NxtRw, "C")
.EntireRow.Insert
.Value = "Total Closed Cases"
End With
'Next Row below
NxtRw = Cells(Rows.Count, "B").End(xlUp).Row + 1
With Cells(NxtRw, "B")
.Formula = "=CountIf(B2:B" & NxtRw - 1 & ", ""Open*"")"
End With
With Cells(NxtRw, "C")
.Formula = "=CountIf(B2:B" & NxtRw - 1 & ", ""Closed*"")"
End With
End Sub
Then you can add the formulas after each new worksheet is created by calling
Insert_Formulas_Into_WorkSheet WSNew