I currently have my macro to separate and create new workbooks for unique values by email address and add the unique value workbooks to a folder.
What I am now trying to do is add to this so that it will do the same thing with a slight twist. I need a folder to be created by a column containing an Organization name (There are about 100 different organizations) and then have it create new workbooks based off of unique values by email address (the same thing it currently does.) I just can't figure out how to add that extra folder of Organization name and still run as it does.
Most of the code I am using I found online, I made a couple slight modifications for my personal use.
Sub Copy_To_Workbooks()
Dim My_Range As Range
Dim FieldNum As Long
Dim FileExtStr As String
Dim FileFormatNum As Long
Dim CalcMode As Long
Dim ViewMode As Long
Dim ws2 As Worksheet
Dim MyPath As String
Dim foldername As String
Dim Lrow As Long
Dim cell As Range
Dim CCount As Long
Dim WSNew As Worksheet
Dim ErrNum As Long
Set My_Range = Range("A1:Q" & 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 workbook"
Exit Sub
End If
FieldNum = 4
'Turn off AutoFilter
My_Range.Parent.AutoFilterMode = False
'Set the file extension/format
If Val(Application.Version) < 12 Then
'You use Excel 97-2003
FileExtStr = ".xls": FileFormatNum = -4143
Else
'You use Excel 2007-2013
If ActiveWorkbook.FileFormat = 56 Then
FileExtStr = ".xls": FileFormatNum = 56
Else
FileExtStr = ".xlsx": FileFormatNum = 51
End If
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
'Delete the sheet RDBLogSheet if it exists
On Error Resume Next
Application.DisplayAlerts = False
Sheets("RDBLogSheet").Delete
Application.DisplayAlerts = True
On Error GoTo 0
' Add worksheet to copy/Paste the unique list
Set ws2 = Worksheets.Add(After:=Sheets(Sheets.Count))
ws2.Name = "RDBLogSheet"
'Fill in the path\folder where you want the new folder with the files
MyPath = “U:\Updates”
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
foldername = MyPath & Format("Helper Cases") & "\"
MkDir foldername
With ws2
'first we copy the Unique data from the filter field to ws2
My_Range.Columns(FieldNum).AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=.Range("A3"), 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("A4: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 new workbook with one sheet
Set WSNew = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
'Copy/paste the visible data to the new workbook
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
'Save the file in the new folder and close it
On Error Resume Next
WSNew.Parent.SaveAs foldername & _
cell.Value & FileExtStr, FileFormatNum
If Err.Number > 0 Then
Err.Clear
ErrNum = ErrNum + 1
WSNew.Parent.SaveAs foldername & _
"Error_" & Format(ErrNum, "0000") & FileExtStr, FileFormatNum
.Cells(cell.Row, "B").Formula = "=Hyperlink(""" & foldername & _
"Error_" & Format(ErrNum, "0000") & FileExtStr & """)"
.Cells(cell.Row, "A").Interior.Color = vbRed
Else
.Cells(cell.Row, "B").Formula = _
"=Hyperlink(""" & foldername & cell.Value & FileExtStr & """)"
End If
WSNew.Parent.Close False
On Error GoTo 0
End If
'Show all the data in the range
My_Range.AutoFilter Field:=FieldNum
Next cell
.Cells(1, "A").Value = "Red cell: can't use the Unique name as file name"
.Cells(1, "B").Value = "Created Files (Click on the link to open a file)"
.Cells(3, "A").Value = "Unique Values"
.Cells(3, "B").Value = "Full Path and File name"
.Cells(3, "A").Font.Bold = True
.Cells(3, "B").Font.Bold = True
.Columns("A:B").AutoFit
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
ws2.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
Related
I am very new to VBA Macro, I am trying to create a macro that split data based on a specific column and creates a new workbook for each column values.
Below is my code which gives a lot of errors I am confused to deal with it... the below code is too lengthy is there any way possible to short main is the proper output
Sub ExportData()
'Declare variables
Dim ArrayItem As Long
Dim ws As Worksheet
Dim ArrayOfUniqueValues As Variant
Dim SavePath As String
Dim ColumnHeadingInt As Long
Dim ColumnHeadingStr As String
Dim rng As Range
'Set the worksheet to
Set ws = Sheets("POL")
'Set the save path for the files created
SavePath = "C:\Folder"
'Set variables for the column we want to separate data based on
ColumnHeadingInt = ActiveWorkbook.Worksheets("POL").Match(Range("Carrier").Value, Range("POL[#Headers]"), 0)
ColumnHeadingStr = "POL[[#All],[" & Range("Carrier").Value & "]]"
'Turn off screen updating to save runtime
Application.ScreenUpdating = False
'Create a temporary list of unique values from the column we want to
'separate our data based on
Range(ColumnHeadingStr & "").AdvancedFilter Action:=xlFilterCopy, _
CopyToRange:=Range("UniqueValues"), Unique:=True
'Sort our temporary list of unique values
ws.Range("UniqueValues").EntireColumn.Sort Key1:=ws.Range("UniqueValues").Offset(1, 0), _
Order1:=xlAscending, Header:=xlYes, OrderCustom:=1, MatchCase:=False, _
Orientation:=xlTopToBottom, DataOption1:=xlSortNormal
'Add unique field values into an array
'ArrayOfUniqueValues = Application.WorksheetFunction.Transpose(ws.Range("IV2:IV" & Rows.Count).SpecialCells(xlCellTypeConstants))
ArrayOfUniqueValues = Application.WorksheetFunction.Transpose(ws.Range("UniqueValues").EntireColumn.SpecialCells(xlCellTypeConstants))
'Delete the temporary values
ws.Range("UniqueValues").EntireColumn.Clear
'Loop through our array of unique field values, copy paste into new workbooks and save
For ArrayItem = 1 To UBound(ArrayOfUniqueValues)
ws.ListObjects("POL").Range.AutoFilter Field:=ColumnHeadingInt, Criteria1:=ArrayOfUniqueValues(ArrayItem)
ws.Range("POL[#All]").SpecialCells(xlCellTypeVisible).Copy
Workbooks.Add
Range("A1").PasteSpecial xlPasteAll
ActiveWorkbook.SaveAs SavePath & ArrayOfUniqueValues(ArrayItem) & Format(Now(), " YYYY-MM-DD ") & ".xlsx", 51
ActiveWorkbook.Close False
ws.ListObjects("POL").Range.AutoFilter Field:=ColumnHeadingInt
Next ArrayItem
ws.AutoFilterMode = False
MsgBox "Finished exporting!"
Application.ScreenUpdating = True
End Sub
Border got added to all the empty cells also
I coded like this
'Autofit
Sheets("POL").UsedRange.Columns.AutoFit
'Sorting the range to compact the data.
With .Parent.Sort
.SortFields.Clear
.SortFields.Add Key:=RngRange02.Columns(DblCarrierColumnRelativeColumn), _
SortOn:=xlSortOnValues, _
Order:=xlAscending, _
DataOption:=xlSortNormal
.SetRange RngRange02
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'Apply Border
With Sheets("POL").UsedRange.Borders
.LineStyle = xlContinuous
.Weight = xlThin
.ColorIndex = xlAutomatic
End With
I have added 3 more set that changes the sheetname and autofits the column in all excel sheet. All it is working but the problem is with the border which is applying to the empty cells also
Try this:
Sub ExportAndSave()
'Declarations.
Dim RngSourceData As Range
Dim RngTarget As Range
Dim RngRange01 As Range
Dim RngRange02 As Range
Dim StrCarrierColumnHeader As String
Dim StrSavePath As String
Dim StrMultipleFileMessage As String
Dim DblCarrierColumnRelativeColumn As Double
Dim DblCounter01 As Double
Dim DblCounter02 As Double
Dim WkbSource As Workbook
Dim WkbTarget As Workbook
'Turning off screen updating.
Application.ScreenUpdating = False
'Setting variables.
Set WkbSource = ActiveWorkbook
Set RngSourceData = WkbSource.Sheets("POL").Range("I1:J6")
StrCarrierColumnHeader = "Carrier"
StrSavePath = "C:\Folder\"
'Setting DblCarrierColumnRelativeColumn to determine what column within RngSourceData _
contains the StrCarrierColumnHeader. If no such column is found, the subroutine is terminated.
On Error Resume Next
DblCarrierColumnRelativeColumn = Excel.WorksheetFunction.Match(StrCarrierColumnHeader, RngSourceData.Rows(1), 0)
If Err <> 0 Then
MsgBox "The range " & RngSourceData.Rows(1).Address(False, False) & " contains no column headed " & StrCarrierColumnHeader & ". The subroutine is terminated", vbCritical, "Error"
Application.ScreenUpdating = True
Exit Sub
End If
On Error GoTo 0
'Setting RngRange01 to cover the data in the carrier column.
Set RngRange01 = RngSourceData.Columns(DblCarrierColumnRelativeColumn).Resize(RngSourceData.Rows.Count - 1).Offset(1, 0)
'Covering each cell in RngRange01.
DblCounter01 = 0
For Each RngTarget In RngRange01.Cells
'Checking if the code had already met the carrier of RngTarget.
If Excel.WorksheetFunction.CountIf(RngSourceData.Parent.Range(RngRange01.Cells(1, 1), RngTarget), RngTarget.Value) = 1 Then
'Cheking if any file dedicated to the given carrier already exists for today.
If Dir(StrSavePath & RngTarget.Value & Format(Now(), " YYYY-MM-DD ") & ".xlsx") = "" Then
'If no such file exists, it is created and saved.
Set WkbTarget = Workbooks.Add
WkbTarget.SaveAs StrSavePath & RngTarget.Value & Format(Now(), " YYYY-MM-DD ") & ".xlsx"
Else
'Is it does exist, the name is "shifted".
DblCounter02 = 2
Do Until Dir(StrSavePath & RngTarget.Value & Format(Now(), " YYYY-MM-DD ") & "(" & DblCounter02 & ")" & ".xlsx") = ""
DblCounter02 = DblCounter02 + 1
Loop
'Carrier and relative file are copied in StrMultipleFileMessage.
StrMultipleFileMessage = StrMultipleFileMessage & vbCrLf & RngTarget.Value & " in " & RngTarget.Value & Format(Now(), " YYYY-MM-DD ") & "(" & DblCounter02 & ")" & ".xlsx"
Set WkbTarget = Workbooks.Add
WkbTarget.SaveAs StrSavePath & RngTarget.Value & Format(Now(), " YYYY-MM-DD ") & "(" & DblCounter02 & ")" & ".xlsx"
End If
'Setting RngRange02 to target the range in the new file where RngSourceData will be copied.
Set RngRange02 = WkbTarget.Sheets(1).Range("A1").Resize(RngSourceData.Rows.Count, RngSourceData.Columns.Count)
With RngRange02
'Copying values.
RngSourceData.Copy RngRange02
'Filtering the range to clear the list of unwanted data.
.AutoFilter Field:=DblCarrierColumnRelativeColumn, Criteria1:="<>" & RngTarget.Value
.Resize(.Rows.Count - 1, .Columns.Count).Offset(1, 0).ClearContents
.Resize(.Rows.Count - 1, .Columns.Count).Offset(1, 0).ClearFormats
'Removing the filter.
.AutoFilter
'Sorting the range to compact the data.
With .Parent.Sort
.SortFields.Clear
.SortFields.Add Key:=RngRange02.Columns(DblCarrierColumnRelativeColumn), _
SortOn:=xlSortOnValues, _
Order:=xlAscending, _
DataOption:=xlSortNormal
.SetRange RngRange02
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End With
'Saving and closing WkbTarget.
WkbTarget.Close savechanges:=True
End If
'Setting DblCounter01.
DblCounter01 = DblCounter01 + 1
Next
'Enabling screen updating.
Application.ScreenUpdating = True
'Reporting if any carrier had its data reported in a "twin" file.
If StrMultipleFileMessage <> "" Then
StrMultipleFileMessage = "The following carriers had already one or more dedicated files at the given path. Their data were saved accordingly to this list:" & vbCrLf & vbCrLf & StrMultipleFileMessage
MsgBox StrMultipleFileMessage, , "Multiple dedicated files"
End If
End Sub
You will probably have to edit the setting of some variables (RngSourceData for sure i'd say).
There are answers to this question using a single filter. BUT How do you split a worksheet into multiple worksheets based off of more than 1 filter (column). I have this worksheet below.
Name Age Branch Section Dept
Bob 20 1 2 A
Bill 20 1 2 A
Jill 20 1 2 B
Jane 20 1 3 A
Paul 20 2 3 B
Tom 20 2 3 B
I want to split this into multiple worksheets based off of 3 columns (Branch, Section, Dept). The results should look like this:
Name Age Branch Section Dept
Bob 20 1 2 A
Bill 20 1 2 A
Name Age Branch Section Dept
Jill 20 1 2 B
Name Age Branch Section Dept
Jane 20 1 3 A
Name Age Branch Section Dept
Paul 20 2 3 B
Tom 20 2 3 B
How would I write a VBA Excel macro to do this?
Also each worksheet should be named "BRANCH" # & "SECTION" # & "DEPT" letter. (e.g. BRANCH1SECTION2DEPTA)
Currently, I have this VBA code that can do this filtering for 1 column.
Sub SplitandFilterSheet()
'Step 1 - Name your ranges and Copy sheet
'Step 2 - Filter by Department and delete rows not applicable
'Step 3 - Loop until the end of the list
Dim Splitcode As Range
Sheets("Master").Select
Set Splitcode = Range("Splitcode")
For Each cell In Splitcode
Sheets("Master").Copy After:=Worksheets(Sheets.Count)
ActiveSheet.Name = cell.Value
With ActiveWorkbook.Sheets(cell.Value).Range("MasterData")
.AutoFilter Field:=6, Criteria1:="NOT EQUAL TO" & cell.Value, Operator:=xlFilterValues
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
ActiveSheet.AutoFilter.ShowAllData
Next cell
End Sub
I just hacked this together. It seems to do what you described. Notice, I copied the data from C1:E7 and pasted it into AA1, then clicked Data > Remove Duplicates. You can record a Macro to do this and add it to the code, towards the top.
Sub Copy_To_Worksheets()
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 My_Range = Range("A1:E" & LastRow(ActiveSheet))
My_Range.Parent.Select
'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 ws = Worksheets("Data")
With ws
Lrow = .Cells(Rows.Count, "A").End(xlUp).Row
'For Each cell In .Range("A2:A" & Lrow)
For Each c In Range("AA2:AA5")
'Filter the range
My_Range.AutoFilter Field:=3, Criteria1:="=" & c.Value
My_Range.AutoFilter Field:=4, Criteria1:="=" & c.Offset(0, 1).Value
My_Range.AutoFilter Field:=5, Criteria1:="=" & c.Offset(0, 2).Value
Set WSNew = Worksheets.Add(After:=Sheets(Sheets.Count))
On Error Resume Next
WSNew.Name = "Branch" & c.Value & "Section" & c.Offset(0, 1).Value & "Dept" & c.Offset(0, 2).Value
On Error GoTo 0
'Copy the visible data to the new worksheet
My_Range.SpecialCells(xlCellTypeVisible).Copy
With WSNew.Range("A1")
.PasteSpecial Paste:=8
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
.Select
End With
Next c
'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
Before:
After:
I am adding some modified code below, to address your last question. Use the code below, and keep the Function named 'LastRow'.
Sub TryThis()
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 My_Range = Range("A1:E" & LastRow(ActiveSheet))
My_Range.Parent.Select
'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 ws = Worksheets("Data")
With ws
Lrow = .Cells(Rows.Count, "A").End(xlUp).Row
For Each c In Range("AA2:AA5")
'Filter the range
My_Range.AutoFilter Field:=3, Criteria1:="=" & c.Value
My_Range.AutoFilter Field:=4, Criteria1:="=" & c.Offset(0, 1).Value
My_Range.AutoFilter Field:=5, Criteria1:="=" & c.Offset(0, 2).Value
Set WSNew = Worksheets.Add(After:=Sheets(Sheets.Count))
On Error Resume Next
WSNew.Name = "Branch" & c.Value & "Section" & c.Offset(0, 1).Value & "Dept" & c.Offset(0, 2).Value
On Error GoTo 0
'Copy the visible data to the new worksheet
My_Range.SpecialCells(xlCellTypeVisible).Copy
With WSNew.Range("A1")
.PasteSpecial Paste:=8
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
.Select
End With
Columns("C:E").Select
Selection.ClearContents
Next c
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
I have an excel sheet which has consolidated yearly data .
For eg : each year 2014 , 2015 , 2016 has multiple rows
I need to split this data and create one sheet for each year and the name of the sheet should be the year.
What I did was to create a pivot by year and click on the count . It would create a new sheet only for that year and then I change the name of the sheet to the year
Is there any simple way of doing it ? I have to do this for many excels and I am manually creating a pivot and clicking on each count cell .
Let me know if there is any automated way of achieving this using VB script or to click all counts at once in a pivot table so that multiple sheets can get generated
Try it this way.
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
Before:
After:
I have a workbook already with a macro that does several things based on a cell value:
When i change a cell value (its a store name) the code will filter several sheets with, just to show the store of that specific cell, then hides several sheets.
Just showing 2 specific sheets.
And in the end of the code i save a new workbook with the name of that store.
My question is:
Is it possible to change my code (shown below), so i dont have to write manually the name of the store, ie, i want that the macro sees a list of stores, then change the cell with each store, do all the tasks i want, and then writes a new workbook with that store name, and so on, until the end of the list store?
Thank you so much
(PS: im new in vba, so my code probably is a little rough around the edges)
Sub Nova_loja()
Dim sht As Worksheet
Dim Fname As String
Dim Cell As Range, cRange As Range
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
'copy past in values
With Range("K44:L66")
.Cells.Copy
.Cells.PasteSpecial xlPasteValues
End With
Application.CutCopyMode = False
'filter and delete
Sheets("BD Geral").Select
ActiveSheet.ListObjects("Table2").Range.AutoFilter Field:=52, Criteria1:="<>" & Worksheets("Tabela - Média Mensal").Range("B2").value, Operator:=xlFilterValues
Application.DisplayAlerts = False
ActiveSheet.ListObjects("Table2").DataBodyRange.SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
ActiveSheet.ListObjects("Table2").AutoFilter.ShowAllData
'filter and delete
Sheets("BD BONUS_MALUS").Select
ActiveSheet.ListObjects("Table35").Range.AutoFilter Field:=3, Criteria1:="<>" & Worksheets("Tabela - Média Mensal").Range("B1").value, Operator:=xlFilterValues
Application.DisplayAlerts = False
ActiveSheet.ListObjects("Table35").DataBodyRange.SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
ActiveSheet.ListObjects("Table35").AutoFilter.ShowAllData
'filter and delete
Sheets("BD NPS").Select
ActiveSheet.ListObjects("Table3").Range.AutoFilter Field:=2, Criteria1:="<>" & Worksheets("Tabela - Média Mensal").Range("B1").value, Operator:=xlFilterValues
Application.DisplayAlerts = False
ActiveSheet.ListObjects("Table3").DataBodyRange.SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
ActiveSheet.ListObjects("Table3").AutoFilter.ShowAllData
Sheets("BD Dept").Select
ActiveSheet.ListObjects("Table4").Range.AutoFilter Field:=8, Criteria1:="<>" & Worksheets("Tabela - Média Mensal").Range("B1").value, Operator:=xlFilterValues
Application.DisplayAlerts = False
ActiveSheet.ListObjects("Table4").DataBodyRange.SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
ActiveSheet.ListObjects("Table4").AutoFilter.ShowAllData
'refresh pivots
ThisWorkbook.RefreshAll
'hide sheets
For Each sht In ThisWorkbook.Worksheets
If sht.Name <> "Dashboard" And sht.Name <> "Tabela - Média Mensal" Then
sht.Visible = xlSheetVeryHidden
End If
Next sht
'protect sheets
For Each sht In ActiveWorkbook.Sheets
sht.Protect Password:="fnacrh", AllowSorting:=True, AllowFiltering:=True, AllowUsingPivotTables:=True
Next
'leave active main worksheet
Sheets("Dashboard").Select
'save as with new name
Application.DisplayAlerts = False
Fname = ThisWorkbook.Path & "\" & "02.VIM_REPORT MENSAL - " & Worksheets("aux").Range("V2") & " - " & Worksheets("aux").Range("V3") & ".xlsx"
ActiveWorkbook.SaveAs Filename:=Fname, FileFormat:=xlWorkbookDefault
Application.DisplayAlerts = True
Application.DisplayStatusBar = True
Application.ScreenUpdating = True
End Sub
Thank you so much
The next code would do what I understood you need.
Copy the next code in a module of another workbook, different from the one to be processed, and run AutomaticallySelectStore procedure. An InputBox will appear asking to select the number from the right side of the workbook name to be processed.
Sub AutomaticallySelectStore()
Dim w As Workbook, Wb As Workbook, sh As Worksheet, store As Variant, Arr As Variant, Ans As String
Dim i As Long, strWorkb As String, strWbName As String, strWbPath As String, nrStores As Long
strWorkb = "Please write the number of the workbook needed to be processed:" & vbCrLf & vbCrLf
For Each Wb In Workbooks
i = i + 1
strWorkb = strWorkb & Wb.name & " - " & i & vbCrLf
Next
strWorkb = left(strWorkb, Len(strWorkb) - 1)
Ans = InputBox(strWorkb, "Necessary workbook selection", 1)
If Ans = "" Then MsgBox "You did not select anything...", vbInformation, "No workbook selected": Exit Sub
If Not IsNumeric(Ans) Then
MsgBox "You must write the number from the right side of the needed workbook name!", vbInformation, _
"Wrong choice...": Exit Sub
ElseIf Ans > Workbooks.Count Then
MsgBox "You must write a number less or equal with " & Workbooks.Count, vbInformation, _
"Wrong chosen number": Exit Sub
End If
Set w = Workbooks(CLng(Ans))
On Error Resume Next
Set sh = w.Worksheets("aux")
If Err.Number <> 0 Then
Err.Clear: On Error GoTo 0
MsgBox "The chosen workbook looks to be wrong..." & vbCrLf & _
" Worksheet ""Tabela - Média Mensal"" is missing.", vbInformation, _
"Wrong workbook or necessary worksheet missing": Exit Sub
End If
On Error GoTo 0
strWbName = w.FullName
nrStores = sh.Range("AF2").End(xlDown).Row
Arr = sh.Range("AF2:AF" & nrStores)
w.Activate
i = 0
Application.Calculation = xlCalculationManual
For Each store In Arr
i = i + 1
Nova_loja strWbName, store, i, nrStores - 1
Next
Application.Calculation = xlCalculationAutomatic
Application.StatusBar = "Ready..."
End Sub
Sub Nova_loja(strWbName As String, store As Variant, No As Long, NrPag As Long)
Dim sht As Worksheet, fName As String, Cell As Range, cRange As Range
Dim w As Workbook, Wb As Workbook, boolFound As Boolean, shortName As String
Dim Arr As Variant, shAr As Worksheet, shortWbName As String
shortWbName = Right(strWbName, Len(strWbName) - InStrRev(strWbName, "\"))
For Each Wb In Workbooks
If Wb.FullName = strWbName Then
Set w = Wb: boolFound = True: Exit For
End If
Next
If Not boolFound Then
Set w = Workbooks.Open(strWbName)
End If
Application.ScreenUpdating = False
Application.StatusBar = "Working on " & store & " store (" & No & " of " & NrPag & ")..."
Application.CalculateBeforeSave = True
Set shAr = Workbooks(shortWbName).Worksheets("aux")
Arr = shAr.Range("K44:L66")
shAr.Range("K44:L66") = Arr
Sheets("Tabela - Média Mensal").Range("B2").Value = store
Sheets("BD Geral").ListObjects("Table2").Range.AutoFilter field:=52, Criteria1:="<>" & store, _
Operator:=xlFilterValues
Application.DisplayAlerts = False
Sheets("BD Geral").ListObjects("Table2").DataBodyRange.SpecialCells(xlCellTypeVisible).Delete
Sheets("BD Geral").ListObjects("Table2").AutoFilter.ShowAllData 'it returns an error if no filter is applied
Application.DisplayAlerts = True
'filter and delete
Sheets("BD BONUS_MALUS").ListObjects("Table35").Range.AutoFilter field:=3, Criteria1:="<>" & Worksheets("Tabela - Média Mensal").Range("B1").Value, Operator:=xlFilterValues
Application.DisplayAlerts = False
Sheets("BD BONUS_MALUS").ListObjects("Table35").DataBodyRange.SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
Sheets("BD BONUS_MALUS").ListObjects("Table35").AutoFilter.ShowAllData
'filter and delete
Sheets("BD NPS").ListObjects("Table3").Range.AutoFilter field:=2, Criteria1:="<>" & Worksheets("Tabela - Média Mensal").Range("B1").Value, Operator:=xlFilterValues
Application.DisplayAlerts = False
Sheets("BD NPS").ListObjects("Table3").DataBodyRange.SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
Sheets("BD NPS").ListObjects("Table3").AutoFilter.ShowAllData
'This sheet does not contain any "Table"...
Sheets("BD Dept").ListObjects("Table4").Range.AutoFilter field:=8, Criteria1:="<>" & Worksheets("Tabela - Média Mensal").Range("B1").Value, Operator:=xlFilterValues
Application.DisplayAlerts = False
Sheets("BD Dept").ListObjects("Table4").DataBodyRange.SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
Sheets("BD Dept").ListObjects("Table4").AutoFilter.ShowAllData
'hide sheets
For Each sht In w.Worksheets
If sht.name <> "Dashboard" And sht.name <> "Tabela - Média Mensal" Then
sht.Visible = xlSheetVeryHidden
End If
Next sht
'protect sheets
For Each sht In ActiveWorkbook.Sheets
sht.Protect Password:="fnacrh", AllowSorting:=True, AllowFiltering:=True, AllowUsingPivotTables:=True
Next
'leave active main worksheet
Sheets("Dashboard").Select
w.RefreshAll
shortName = "02.VIM_REPORT MENSAL - " & store & " - " & Worksheets("aux").Range("V3") & ".xlsx"
fName = w.Path & "\" & shortName
Application.DisplayAlerts = False
ActiveWorkbook.SaveAs Filename:=fName, FileFormat:=xlWorkbookDefault
Workbooks(shortName).Close , False
Application.DisplayAlerts = True
Application.DisplayStatusBar = True
Application.ScreenUpdating = True
End Sub
Please, test it and confirm if it works as expected.
If not, mention what wrong happens.
Would that 'list of stores' be another excel workbook/sheet?
Do we have to deduce where the 'store' in discussion exists in your workbook?
Isn't it better you to describe where the change must be done?
Of course, this is not an answer but I do not know how else I can clarify the issue...
Sub AutomaticallySelectStore()
Dim W As Workbook, Sh As Worksheet, store As Variant, Arr As Variant
Set W = ActiveWorkbook
Set Sh = W.Worksheets("Tabela - Média Mensal")
Arr = Sh.Range("AF2:AF" & Sh.Range("AF2").SpecialCells(xlCellTypeLastCell).Row)
For Each store In Arr
Nova_loja store
Next
End Sub
Sub Nova_loja(store As Variant)
Dim sht As Worksheet, Fname As String, Cell As Range, cRange As Range
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
With Range("K44:L66")
.Cells.Copy
.Cells.PasteSpecial xlPasteValues
End With
Application.CutCopyMode = False
'filter and delete
Sheets("BD Geral").Select
ActiveSheet.ListObjects("Table2").Range.AutoFilter Field:=52, Criteria1:="<>" & store, Operator:=xlFilterValues
Application.DisplayAlerts = False
ActiveSheet.ListObjects("Table2").DataBodyRange.SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
ActiveSheet.ListObjects("Table2").AutoFilter.ShowAllData
'filter and delete
Sheets("BD BONUS_MALUS").Select
ActiveSheet.ListObjects("Table35").Range.AutoFilter Field:=3, Criteria1:="<>" & Worksheets("Tabela - Média Mensal").Range("B1").Value, Operator:=xlFilterValues
Application.DisplayAlerts = False
ActiveSheet.ListObjects("Table35").DataBodyRange.SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
ActiveSheet.ListObjects("Table35").AutoFilter.ShowAllData
'filter and delete
Sheets("BD NPS").Select
ActiveSheet.ListObjects("Table3").Range.AutoFilter Field:=2, Criteria1:="<>" & Worksheets("Tabela - Média Mensal").Range("B1").Value, Operator:=xlFilterValues
Application.DisplayAlerts = False
ActiveSheet.ListObjects("Table3").DataBodyRange.SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
ActiveSheet.ListObjects("Table3").AutoFilter.ShowAllData
Sheets("BD Dept").Select
ActiveSheet.ListObjects("Table4").Range.AutoFilter Field:=8, Criteria1:="<>" & Worksheets("Tabela - Média Mensal").Range("B1").Value, Operator:=xlFilterValues
Application.DisplayAlerts = False
ActiveSheet.ListObjects("Table4").DataBodyRange.SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
ActiveSheet.ListObjects("Table4").AutoFilter.ShowAllData
'refresh pivots
ThisWorkbook.RefreshAll
'hide sheets
For Each sht In ThisWorkbook.Worksheets
If sht.Name <> "Dashboard" And sht.Name <> "Tabela - Média Mensal" Then
sht.Visible = xlSheetVeryHidden
End If
Next sht
'protect sheets
For Each sht In ActiveWorkbook.Sheets
sht.Protect Password:="fnacrh", AllowSorting:=True, AllowFiltering:=True, AllowUsingPivotTables:=True
Next
'leave active main worksheet
Sheets("Dashboard").Select
'save as with new name
Application.DisplayAlerts = False
Fname = ThisWorkbook.Path & "\" & "02.VIM_REPORT MENSAL - " & Worksheets("aux").Range("V2") & " - " & Worksheets("aux").Range("V3") & ".xlsx"
ActiveWorkbook.SaveAs Filename:=Fname, FileFormat:=xlWorkbookDefault
Application.DisplayAlerts = True
Application.DisplayStatusBar = True
Application.ScreenUpdating = True
End Sub
So, you must run 'AutomaticallySelectStore' procedure and wait...
I do not have such a file in order to test it, so, it is a code based only on VBA logic and my understanding about your situation.
Depending on how big are your workbooks it may load your system RAM and CPU, working continuously. I am waiting for some feedback.
The initial code can also be optimized a little, but let us see how it works now.
I'm looking to split my data into multiple workbooks that will carry the name of my "unique value".
Need to perform this several times per month, so am looking for an automated solution.
I have about 20 columns, column A contains the unique value, which can be repeated several times. The other columns carry information regarding the the unique value.
I would also prefer if the original formatting of the file remains.
The unique value repeats itself in a random order, but I want all of them to be grouped in 1 file, in the same order (if possible)
I had found another code, but it is not working because my values repeat themselves.
Sub Copy_To_Workbooks()
'Note: This macro use the function LastRow
Dim My_Range As Range
Dim FieldNum As Long
Dim FileExtStr As String
Dim FileFormatNum As Long
Dim CalcMode As Long
Dim ViewMode As Long
Dim ws2 As Worksheet
Dim MyPath As String
Dim foldername As String
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 workbook"
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
'Set the file extension/format
If Val(Application.Version) < 12 Then
'You use Excel 97-2003
FileExtStr = ".xls": FileFormatNum = -4143
Else
'You use Excel 2007-2013
If ActiveWorkbook.FileFormat = 56 Then
FileExtStr = ".xls": FileFormatNum = 56
Else
FileExtStr = ".xlsx": FileFormatNum = 51
End If
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
'Delete the sheet RDBLogSheet if it exists
On Error Resume Next
Application.DisplayAlerts = False
Sheets("RDBLogSheet").Delete
Application.DisplayAlerts = True
On Error GoTo 0
' Add worksheet to copy/Paste the unique list
Set ws2 = Worksheets.Add(After:=Sheets(Sheets.Count))
ws2.Name = "RDBLogSheet"
'Fill in the path\folder where you want the new folder with the files
'you can use also this "C:\Users\Ron\test"
MyPath = Application.DefaultFilePath
'Add a slash at the end if the user forget it
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
'Create folder for the new files
foldername = MyPath & Format(Now, "yyyy-mm-dd hh-mm-ss") & "\"
MkDir foldername
With ws2
'first we copy the Unique data from the filter field to ws2
My_Range.Columns(FieldNum).AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=.Range("A3"), 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("A4: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 new workbook with one sheet
Set WSNew = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
'Copy/paste the visible data to the new workbook
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
'Save the file in the new folder and close it
On Error Resume Next
WSNew.Parent.SaveAs foldername & _
cell.Value & FileExtStr, FileFormatNum
If Err.Number > 0 Then
Err.Clear
ErrNum = ErrNum + 1
WSNew.Parent.SaveAs foldername & _
"Error_" & Format(ErrNum, "0000") & FileExtStr, FileFormatNum
.Cells(cell.Row, "B").Formula = "=Hyperlink(""" & foldername & _
"Error_" & Format(ErrNum, "0000") & FileExtStr & """)"
.Cells(cell.Row, "A").Interior.Color = vbRed
Else
.Cells(cell.Row, "B").Formula = _
"=Hyperlink(""" & foldername & cell.Value & FileExtStr & """)"
End If
WSNew.Parent.Close False
On Error GoTo 0
End If
'Show all the data in the range
My_Range.AutoFilter Field:=FieldNum
Next cell
.Cells(1, "A").Value = "Red cell: can't use the Unique name as file name"
.Cells(1, "B").Value = "Created Files (Click on the link to open a file)"
.Cells(3, "A").Value = "Unique Values"
.Cells(3, "B").Value = "Full Path and File name"
.Cells(3, "A").Font.Bold = True
.Cells(3, "B").Font.Bold = True
.Columns("A:B").AutoFit
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
ws2.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
Sub t()
On Error Resume Next
Application.DisplayAlerts = False
Dim new_book As Workbook
Dim newsheet As Worksheet
With ThisWorkbook.Sheets("Hierarchy") 'Replace the sheet name with the raw data sheet name
Set newsheet = ThisWorkbook.Sheets("cal")
If newsheet Is Nothing Then
Worksheets.Add.Name = "cal"
Else
ThisWorkbook.Sheets("cal").Delete
Worksheets.Add.Name = "cal"
End If
.Columns("a").Copy
With ThisWorkbook.Sheets("cal")
.Range("a1").PasteSpecial (xlPasteAll)
.Columns("a").RemoveDuplicates Columns:=1, Header:=xlYes
End With
For Each cell In ThisWorkbook.Sheets("cal").Columns("a").Cells
i = i + 1
If i <> 1 And cell.Value <> "" Then
.AutoFilterMode = False
.Rows(1).AutoFilter field:=3, Criteria1:=cell.Value
Set new_book = Workbooks.Add
.UsedRange.Copy
new_book.Sheets(1).Range("a1").PasteSpecial (xlPasteAll)
new_book.SaveAs Filename:=ThisWorkbook.Path & "\" & cell.Value & ".xlsx"
new_book.Sheets(1).UsedRange.Columns.AutoFit
new_book.Save
new_book.Close
End If
Next cell
ThisWorkbook.Sheets("cal").Delete
End With
End Sub