I have a spreadsheet with 800k rows and 150 columns. I'm attempting to create new worksheets based on the contents of a column. So, for example if column Y has many elements ("alpha", "beta", "gamma", etc.) then I'd like to create new worksheets named "alpha", "beta", "gamma" which contain only the rows from the original that have those respective letters. I've found two scripts that work for smaller spreadsheets, but due to the size of this particular spreadsheet, they don't work.
Here are the two scripts that I have tried:
Sub parse_data()
Dim lr As Long
Dim ws As Worksheet
Dim vcol, i As Integer
Dim icol As Long
Dim myarr As Variant
Dim title As String
Dim titlerow As Integer
vcol = 1
Set ws = Sheets("Sheet1")
lr = ws.Cells(ws.Rows.Count, vcol).End(xlUp).Row
title = "A1:C1"
titlerow = ws.Range(title).Cells(1).Row
icol = ws.Columns.Count
ws.Cells(1, icol) = "Unique"
For i = 2 To lr
On Error Resume Next
If ws.Cells(i, vcol) <> "" And Application.WorksheetFunction.Match(ws.Cells(i, vcol), ws.Columns(icol), 0) = 0 Then
ws.Cells(ws.Rows.Count, icol).End(xlUp).Offset(1) = ws.Cells(i, vcol)
End If
Next
myarr = Application.WorksheetFunction.Transpose(ws.Columns(icol).SpecialCells(xlCellTypeConstants))
ws.Columns(icol).Clear
For i = 2 To UBound(myarr)
ws.Range(title).AutoFilter field:=vcol, Criteria1:=myarr(i) & ""
If Not Evaluate("=ISREF('" & myarr(i) & "'!A1)") Then
Sheets.Add(after:=Worksheets(Worksheets.Count)).Name = myarr(i) & ""
Else
Sheets(myarr(i) & "").Move after:=Worksheets(Worksheets.Count)
End If
ws.Range("A" & titlerow & ":A" & lr).EntireRow.Copy Sheets(myarr(i) & "").Range("A1")
Sheets(myarr(i) & "").Columns.AutoFit
Next
ws.AutoFilterMode = False
ws.Activate
End Sub
this returns "overflow"
the other code that I have tried:
Sub columntosheets()
Const sname As String = "VOTERFILE_WITHABSENTEEINFORMATI" 'change to whatever starting sheet
Const s As String = "O" 'change to whatever criterion column
Dim d As Object, a, cc&
Dim p&, i&, rws&, cls&
Set d = CreateObject("scripting.dictionary")
With Sheets(sname)
rws = .Cells.Find("*", , , , xlByRows, xlPrevious).Row
cls = .Cells.Find("*", , , , xlByColumns, xlPrevious).Column
cc = .Columns(s).Column
End With
For Each sh In Worksheets
d(sh.Name) = 1
Next sh
Application.ScreenUpdating = False
With Sheets.Add(after:=Sheets(sname))
Sheets(sname).Cells(1).Resize(rws, cls).Copy .Cells(1)
.Cells(1).Resize(rws, cls).Sort .Cells(cc), 2, Header:=xlYes
a = .Cells(cc).Resize(rws + 1, 1)
p = 2
For i = 2 To rws + 1
If a(i, 1) <> a(p, 1) Then
If d(a(p, 1)) <> 1 Then
Sheets.Add.Name = a(p, 1)
.Cells(1).Resize(, cls).Copy Cells(1)
.Cells(p, 1).Resize(i - p, cls).Copy Cells(2, 1)
End If
p = i
End If
Next i
Application.DisplayAlerts = False
.Delete
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End With
Sheets(sname).Activate
End Sub
Returns error with "excel does not have enough resources".
Is it possible to do what I want on my hardware?
You can refer to the modified subroutine in another article 'Macro for copying and pasting data to another worksheet'.
Sub CopySheet()
Dim wsAll As Worksheet
Dim wsCrit As Worksheet
Dim wsNew As Worksheet
Dim LastRow As Long
Dim LastRowCrit As Long
Dim I As Long
Set wsAll = Worksheets("All") ' change All to the name of the worksheet the existing data is on
LastRow = wsAll.Range("A" & Rows.Count).End(xlUp).Row
Set wsCrit = Worksheets.Add
' column G has the criteria eg project ref
wsAll.Range("A1:A" & LastRow).AdvancedFilter Action:=xlFilterCopy, CopyToRange:=wsCrit.Range("A1"), Unique:=True
LastRowCrit = wsCrit.Range("A" & Rows.Count).End(xlUp).Row
For I = 2 To LastRowCrit
wsAll.Copy Before:=Sheets("All")
ActiveSheet.Name = wsCrit.Range("A2")
Range("A1").CurrentRegion.AdvancedFilter Action:=xlFilterInPlace, CriteriaRange:=wsCrit.Range("A1:A2"), _
Unique:=False
wsCrit.Rows(2).Delete
Next I
Application.DisplayAlerts = False
wsCrit.Delete
Application.DisplayAlerts = True
End Sub
Related
I am trying to split data from an Excel column in to different tabs for each unique value. For example, I'd like a tab for each unique value in the Concat field that lists only the records for that specific person.
Currently using this code, which splits the tabs out correctly, but each tab has all of the worksheet's data, not just the individualized data.
Sub parse_data()
Dim lr As Long
Dim ws As Worksheet
Dim vcol, i As Integer
Dim icol As Long
Dim myarr As Variant
Dim title As String
Dim titlerow As Integer
vcol = 5
Set ws = Sheets("qReconcilers")
lr = ws.Cells(ws.Rows.Count, vcol).End(xlUp).Row
title = "A1:N1"
titlerow = ws.Range(title).Cells(1).Row
icol = ws.Columns.Count
ws.Cells(1, icol) = "Unique"
For i = 2 To lr
On Error Resume Next
If ws.Cells(i, vcol) <> "" And Application.WorksheetFunction.Match(ws.Cells(i, vcol), ws.Columns(icol), 0) = 0 Then
ws.Cells(ws.Rows.Count, icol).End(xlUp).Offset(1) = ws.Cells(i, vcol)
End If
Next
myarr = Application.WorksheetFunction.Transpose(ws.Columns(icol).SpecialCells(xlCellTypeConstants))
ws.Columns(icol).Clear
For i = 2 To UBound(myarr)
ws.Range(title).AutoFilter field:=vcol, Criteria1:=myarr(i) & ""
If Not Evaluate("=ISREF('" & myarr(i) & "'!A1)") Then
Sheets.Add(after:=Worksheets(Worksheets.Count)).Name = myarr(i) & ""
Else
Sheets(myarr(i) & "").Move after:=Worksheets(Worksheets.Count)
End If
ws.Range("A" & titlerow & ":A" & lr).EntireRow.Copy Sheets(myarr(i) & "").Range("A1")
Sheets(myarr(i) & "").Columns.AutoFit
Next
ws.AutoFilterMode = False
ws.Activate
End Sub
How would I get those tabs to only display the data pertaining to that particular person?
Something like this should be ok for a beginning:
Public Sub TestMe()
Dim defaultColumn As Long
defaultColumn = 5 'column E
Dim wks As Worksheet
Dim sourcelastRow As Long
Set wks = Worksheets(1) 'the main worksheet
sourcelastRow = lastRow(wks.Name)
Dim cnt As Long
Dim checkCell As Range
For cnt = 2 To sourcelastRow
Set checkCell = wks.Cells(cnt, defaultColumn)
If WorksheetFunction.IsErr(Evaluate("'" & Trim(checkCell) & "'!A1")) Then
Dim newSheet As Worksheet
Set newSheet = ThisWorkbook.Worksheets.Add(after:=Worksheets(Worksheets.Count))
newSheet.Name = Trim(checkCell.Value2)
End If
Dim targetLastRow As Long
targetLastRow = lastRow(checkCell.Value2) + 1
Worksheets(checkCell.Value2).Rows(targetLastRow).Value2 = wks.Rows(cnt).Value2
Next cnt
End Sub
Public Function lastRow(Optional strSheet As String, _
Optional column_to_check As Long = 1) As Long
Dim shSheet As Worksheet
If strSheet = vbNullString Then
Set shSheet = ActiveSheet
Else
Set shSheet = Worksheets(strSheet)
End If
lastRow = shSheet.Cells(shSheet.Rows.Count, column_to_check).End(xlUp).Row
End Function
What the code does:
loops through every cell in column number 5 of the first worksheet;
checks whether there is a worksheet with the name of this column";
WorksheetFunction.IsErr(Evaluate("'" & Trim(checkCell) & "'!A1"))
if there is no such worksheet - it creates it;
then finds the worksheet with this column and at the row after the last used row of the worksheet it writes the values of the corresponding row;
I have a macro program that parses through a worksheet and creates new work book based on one particular column. In my case new workbooks will be created based on column 3. Also I have written a call function to protect the individual workbooks with a password. Only few columns are editable and the rest of the columns are read only. Now I want to apply auto filter and sort function so that the user can search information based on their need and enter values in the editable cells. However when we protect the sheet autofilter doesn't work. Can you help in adding autofilter function on a protected sheet for each individual workbooks.
Sample code shown for reference.
Sub parse_data()
Dim lr As Long
Dim ws As Worksheet
Dim vcol, i As Integer
Dim icol As Long
Dim myarr As Variant
Dim title As String
Dim titlerow As Integer
vcol = 3
Set ws = Sheets("Sheet1")
lr = ws.Cells(ws.Rows.Count, vcol).End(xlUp).Row
title = "A1:Z1"
titlerow = ws.Range(title).Cells(1).Row
icol = ws.Columns.Count
ws.Cells(1, icol) = "Unique"
For i = 2 To lr
On Error Resume Next
If ws.Cells(i, vcol) <> "" And Application.WorksheetFunction.Match(ws.Cells(i, vcol), ws.Columns(icol), 0) = 0 Then
ws.Cells(ws.Rows.Count, icol).End(xlUp).Offset(1) = ws.Cells(i, vcol)
End If
Next
myarr = Application.WorksheetFunction.Transpose(ws.Columns(icol).SpecialCells(xlCellTypeConstants))
ws.Columns(icol).Clear
For i = 2 To UBound(myarr)
ws.Range(title).AutoFilter field:=vcol, Criteria1:=myarr(i) & ""
If Not Evaluate("=ISREF('" & myarr(i) & "'!A1)") Then
'===================================================================
'~~Sheets.Add(after:=Worksheets(Worksheets.Count)).Name = myarr(i) & ""
Workbooks.Add
ActiveWorkbook.Sheets.Add(0).Name = myarr(i) & ""
'===================================================================
Else
Sheets(myarr(i) & "").Move after:=Worksheets(Worksheets.Count)
End If
'==========================================================================
'~~ws.Range("A" & titlerow & ":A" & lr).EntireRow.Copy Sheets(myarr(i) & "").Range("A1")
'~~Sheets(myarr(i) & "").Columns.AutoFit
ws.Range("A" & titlerow & ":A" & lr).EntireRow.Copy ActiveWorkbook.Sheets("Sheet1").Range("A1")
'mainworkBook.Sheets(1).Range("T2:T1000").Formula = "=SUM(Q2:S2)"
ActiveWorkbook.SaveAs "C:\Macros\Split_Files\" & myarr(i) & ".xlsx"
'=========================================================================
ActiveWorkbook.Close
Next
ws.AutoFilterMode = False
ws.Activate
Call ProtectAll
End Sub
Sub ProtectAll()
Dim wBk As Workbook
Dim sFileSpec As String
Dim sPathSpec As String
Dim sFoundFile As String
Dim mainworkBook As Workbook
Dim ws1 As Worksheet
Dim LastRow As Long
sPathSpec = "C:\Macros\Split_Files\"
sFileSpec = "*.xlsx"
sFoundFile = Dir(sPathSpec & sFileSpec)
Do While sFoundFile <> ""
Set wBk = Workbooks.Open(sPathSpec & sFoundFile)
With wBk
Set mainworkBook = wBk
'mainworkBook.Sheets(1).Unprotect passowrd = "abc"
Set ws1 = mainworkBook.Sheets(1)
LastRow = ws1.Cells(ws1.Rows.Count, "U").End(xlUp).Row
mainworkBook.Sheets(1).Range("U2:U" & LastRow).Formula = "=SUM(R2:T2)"
'mainworkBook.Sheets(1).Range("A:Z").Locked = True
'mainworkBook.Sheets(1).Range("A1:Z1").Locked = False
'mainworkBook.Sheets(1).Range("Q:S").Locked = False
'mainworkBook.Sheets(1).Range("U:U").Locked = False
'mainworkBook.Sheets(1).Range("W:X").Locked = False
mainworkBook.Worksheets("Sheet1").Cells.EntireColumn.AutoFit
'mainworkBook.Sheets(1).Protect passowrd = "abc"
'mainworkBook.Sheets(1).Protect passowrd:="abc", userinterfaceonly:=True
'mainworkBook.Sheets(1).EnableOutlining = True
'mainworkBook.Sheets(1).EnableAutoFilter = True
'mainworkBook.Sheets(1).EnableSelection = xlUnlockedCells
Worksheets(2).Visible = xlSheetHidden
Worksheets(3).Visible = xlSheetHidden
Application.DisplayAlerts = False
wBk.SaveAs Filename:=.FullName
Application.DisplayAlerts = True
End With
Set wBk = Nothing
Workbooks(sFoundFile).Close False
sFoundFile = Dir
Loop
End Sub
Regards,
Linu
In order to sort in a protected sheet you would have to unprotect it and protect it again afterwards.
But you could use the filter function even when the sheet is protected, just not sort.
Here are two little functions I used for on of my projects:
Function protect_sheet(sheetname As String)
If Sheets(sheetname).ProtectContents = False Then
Sheets(sheetname).Protect Password:=Password, DrawingObjects:=True, Contents:=True, Scenarios:=True, AllowSorting:=True, AllowFiltering:=True
End If
End Function
Function unprotect_sheet(sheetname As String)
If Sheets(sheetname).ProtectContents = True Then
Sheets(sheetname).Unprotect Password:=Password
End If
End Function
I need to create new tabs in a workbook based upon a range of cells in a worksheet template. I also want to delete rows of data that do not match the tab name. For example, from the table below I would have a new tab named "2206 - 6" and only data associated with that would remain, keeping in mind that this range of data will change each time the macro is used.
Before:
After:
Interval Number
2206 - 6
6304 - 5
4102 - 20
The table begins in row 11, but I need to retain all of the information above. I have an Advanced Filter Macro that gets close to what I want, but its doing two things I don't want: creating empty tabs and not retaining information above row 11.
Sub parse_data()
Dim lr As Long
Dim ws As Worksheet
Dim vcol, i As Integer
Dim icol As Long
Dim myarr As Variant
Dim title As String
Dim titlerow As Integer
vcol = 1
Set ws = Sheets("Offshore Searches")
lr = ws.Cells(ws.Rows.Count, vcol).End(xlUp).Row
title = "A11:G20"
titlerow = ws.Range(title).Cells(1).Row
icol = ws.Columns.Count
ws.Cells(1, icol) = "Unique"
For i = 2 To lr
On Error Resume Next
If ws.Cells(i, vcol) <> "" And _
Application.WorksheetFunction.Match(ws.Cells(i, vcol), ws.Columns(icol), 0) = 0 Then
ws.Cells(ws.Rows.Count, icol).End(xlUp).Offset(1) = ws.Cells(i, vcol)
End If
Next
myarr = Application.WorksheetFunction.Transpose(ws.Columns(icol).SpecialCells(xlCellTypeConstants))
ws.Columns(icol).Clear
For i = 2 To UBound(myarr)
ws.Range(title).AutoFilter field:=vcol, Criteria1:=myarr(i) & ""
If Not Evaluate("=ISREF('" & myarr(i) & "'!A1)") Then
Sheets.Add(after:=Worksheets(Worksheets.Count)).Name = myarr(i) & ""
Else
Sheets(myarr(i) & "").Move after:=Worksheets(Worksheets.Count)
End If
ws.Range("A" & titlerow & ":A" & lr).EntireRow.Copy Sheets(myarr(i) & "").Range("A1")
Sheets(myarr(i) & "").Columns.AutoFit
Next
ws.AutoFilterMode = False
ws.Activate
End Sub
I also have a macro which creates tabs based on a range without the advanced filter, so each tab looks identical (just the tab name changes)
Sub CreateWorkSheetByRange()
Dim WorkRng As Range
Dim ws As Worksheet
Dim arr As Variant
On Error Resume Next
Set WorkRng = Application.Selection
Set WorkRng = Application.InputBox("Range", xTitleId, WorkRng.Address, Type:=8)
arr = WorkRng.Value
Sheets("Offshore Searches").Select
Cells.Select
Selection.Copy
Application.ScreenUpdating = False
For i = 1 To UBound(arr, 1)
For j = 1 To UBound(arr, 2)
Set ws = Worksheets.Add(after:=Application.ActiveSheet)
ws.Name = arr(i, j)
ActiveSheet.Paste
Range("A1").Select
Next
Next
Application.ScreenUpdating = True
End Sub
Is there a way to both create tabs based on a range while simultaneously using an advanced filter?
Another option (tested)
All functions bellow, in a separate module
It copies the main sheet, deletes the button and uses auto filter to remove unneeded rows
This uses dictionaries and late binding is slow: CreateObject("Scripting.Dictionary")
Early binding is fast: VBA Editor -> Tools -> References -> Add Microsoft Scripting Runtime
Option Explicit
Private Const X As String = vbNullString
Public Sub CreateTabs()
Const FIRST_CELL As String = "Interval Number"
Const LAST_CELL As String = "Vesting Doc Number (LC/RS)"
Dim wb As Workbook, ws As Worksheet, wsNew As Worksheet, d As Dictionary, i As Long
Dim fr As Long, lr As Long, fc As Long, found As Range, rng As Range, val As String
SetDisplay False
Set wb = ThisWorkbook
Set ws = wb.Worksheets("Offshore Searches")
Set found = FindCell(ws.UsedRange, FIRST_CELL)
If Not found Is Nothing Then
fr = found.Row + 1
fc = found.Column
End If
Set found = FindCell(ws.UsedRange, LAST_CELL)
If Not found Is Nothing Then lr = found.Row - 1
If fr > 0 And fc > 0 And lr >= fr Then
If Not ws.AutoFilter Is Nothing Then ws.UsedRange.AutoFilter
Set rng = ws.Range(ws.Cells(fr, fc), ws.Cells(lr, fc))
Dim arr As Variant, r As Long
arr = rng
Set d = New Dictionary
For r = 1 To UBound(arr)
val = Trim(CStr(arr(r, 1)))
val = CleanWsName(val)
If Not d.Exists(val) Then d.Add r, val
Next
For i = 1 To d.Count
If Not WsExists(d(i)) Then
ws.Copy After:=wb.Worksheets(wb.Worksheets.Count)
Set wsNew = wb.Worksheets(wb.Worksheets.Count)
With wsNew
.Name = d(i): If .Shapes.Count = 1 Then wsNew.Shapes.Item(1).Delete
Set rng = .Range(.Cells(fr - 1, fc), .Cells(lr, fc))
rng.AutoFilter Field:=1, Criteria1:="<>" & d(i), Operator:=xlAnd, Criteria2:="<>"
Set rng = rng.Offset(1).Resize(rng.Rows.Count - 1)
rng.SpecialCells(xlCellTypeVisible).EntireRow.Delete Shift:=xlUp
rng.AutoFilter
End With
End If
Next
End If
ws.Activate
SetDisplay True
End Sub
Public Sub SetDisplay(Optional ByVal status As Boolean = False)
Application.ScreenUpdating = status
Application.DisplayAlerts = status
End Sub
Public Function FindCell(ByRef rng As Range, ByVal celVal As String) As Range
Dim found As Range
If Not rng Is Nothing Then
If Len(celVal) > 0 Then
Set found = rng.Find(celVal, MatchCase:=True)
If Not found Is Nothing Then Set FindCell = found
End If
End If
End Function
Public Function CleanWsName(ByVal wsName As String) As String
Const x = vbNullString
wsName = Trim$(wsName) 'Trim, then remove [ ] / \ < > : * ? | "
wsName = Replace(Replace(Replace(wsName, "[", x), "]", x), " ", x)
wsName = Replace(Replace(Replace(wsName, "/", x), "\", x), ":", x)
wsName = Replace(Replace(Replace(wsName, "<", x), ">", x), "*", x)
wsName = Replace(Replace(Replace(wsName, "?", x), "|", x), Chr(34), x)
If Len(wsName) = 0 Then wsName = "DT " & Format(Now, "yyyy-mm-dd hh.mm.ss")
CleanWsName = Left$(wsName, 31) 'Resize to max len of 31
End Function
Public Function WsExists(ByVal wsName As String) As Boolean
Dim ws As Worksheet
With ThisWorkbook
For Each ws In .Worksheets
If ws.Name = wsName Then
WsExists = True
Exit Function
End If
Next
End With
End Function
Assumptions
Interval Numbers format is consistent: Unit & " - " & Week (=B12 & " - " & C12)
Interval Numbers are not longer than 31 character, and don't contain these special chars: [ ] / \ ? * .
If so, the sheet names will be shortened to 31 chars
and all special chars mentioned removed (Excel limitation for Sheet names)
Working row starts after cell "Interval Number" and stop before "Vesting Doc Number (LC/RS)"
There are no spaces before or after "Interval Number" and "Vesting Doc Number (LC/RS)"
Main tab name is exactly "Offshore Searches", and it contains only one button ("Create Tabs")
For what you have shown in the images, you may try something like this to achieve that...
Sub InsertSheets()
Dim sws As Worksheet, ws As Worksheet
Dim slr As Long, i As Long
Dim Rng As Range, Cell As Range
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set sws = Sheets("Sheet1")
If sws.Range("A12").Value = "" Then
MsgBox "No Interval Numbers found on the sheet.", vbExclamation
Exit Sub
End If
slr = sws.Range("A11").End(xlDown).Row
Set Rng = sws.Range("A12:A" & slr)
For Each Cell In Rng
On Error Resume Next
Sheets(Cell.Value).Delete
On Error GoTo 0
sws.Copy after:=Sheets(Sheets.Count)
Set ws = ActiveSheet
ws.Name = Cell.Value
ws.DrawingObjects.Delete
With ws
For i = slr To 12 Step -1
If i <> Cell.Row Then ws.Rows(i).Delete
Next i
End With
Set ws = Nothing
Next Cell
sws.Activate
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
I am very new to the whole VBA scene. I wrote a macro to sort out a table of info into different tabs. From these new tabs, I am wanting to count the number of rows but I found that macro comes up with the error with the macro generated tabs but it works from ones that I manually opened for testing.
Iam trying to get the Sub test() to work but the Sub Parse_data() part is what is generated the new sorted tabs.
' Setting variables
Sub parse_data()
Dim lr As Long
Dim ws As Worksheet
Dim vcol, i As Integer
Dim icol As Long
Dim myarr As Variant
Dim title As String
Dim titlerow As Integer
vcol = 6
Set ws = Sheets("Raw Data")
lr = ws.Cells(ws.Rows.Count, vcol).End(xlUp).Row
title = "A1:K1"
titlerow = ws.Range(title).Cells(1).Row
icol = ws.Columns.Count
ws.Cells(1, icol) = "Unique"
For i = 2 To lr
On Error Resume Next
If ws.Cells(i, vcol) <> "" And Application.WorksheetFunction.Match(ws.Cells(i, vcol), ws.Columns(icol), 0) = 0 Then
ws.Cells(ws.Rows.Count, icol).End(xlUp).Offset(1) = ws.Cells(i, vcol)
End If
Next
myarr = Application.WorksheetFunction.Transpose(ws.Columns(icol).SpecialCells(xlCellTypeConstants))
ws.Columns(icol).Clear
For i = 2 To UBound(myarr)
ws.Range(title).AutoFilter field:=vcol, Criteria1:=myarr(i) & ""
If Not Evaluate("=ISREF('" & myarr(i) & "'!A1)") Then
Sheets.Add(after:=Worksheets(Worksheets.Count)).Name = myarr(i) & ""
Else
Sheets(myarr(i) & "").Move after:=Worksheets(Worksheets.Count)
End If
ws.Range("A" & titlerow & ":A" & lr).EntireRow.Copy Sheets(myarr(i) & "").Range("A1")
Sheets(myarr(i) & "").Columns.AutoFit
Next
ws.AutoFilterMode = False
ws.Activate
End Sub
Sub test()
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Raw data")
Dim k As Long
k = sh.Range("A2", sh.Range("A2").End(xlDown)).Rows.Count
If k = 1048576 Then
k = 1
End If
Sheets("Stats").Range("A2") = k
End Sub
Can anyone help?
Thanks in advance
I would need to split an existing Excel worksheet into different ones. Specifically, I need the new worksheets to be created so that all the rows that have the same content in the cell in column A (in the original worksheet) are put in the same worksheet.
I have found different VBA codes online, but none of them seem to work for me.
The one that doesn't have bug is the one below. It's creating different worksheets, naming them based on the info contained in column A in the original worksheet, but it's not splitting the rows (all the worksheets end up with the same data).
Could you please help?
Thanks!
Sub parse_data()
Dim lr As Long
Dim ws As Worksheet
Dim vcol, i As Integer
Dim icol As Long
Dim myarr As Variant
Dim title As String
Dim titlerow As Integer
vcol = 1
Set ws = Sheets("Sheet1")
lr = ws.Cells(ws.Rows.Count, vcol).End(xlUp).Row
title = "A1:C1"
titlerow = ws.Range(title).Cells(1).Row
icol = ws.Columns.Count
ws.Cells(1, icol) = "Unique"
For i = 2 To lr
On Error Resume Next
If ws.Cells(i, vcol) <> "" And Application.WorksheetFunction.Match(ws.Cells(i, vcol), ws.Columns(icol), 0) = 0 Then
ws.Cells(ws.Rows.Count, icol).End(xlUp).Offset(1) = ws.Cells(i, vcol)
End If
Next
myarr = Application.WorksheetFunction.Transpose(ws.Columns(icol).SpecialCells(xlCellTypeConstants))
ws.Columns(icol).Clear
For i = 2 To UBound(myarr)
ws.Range(title).AutoFilter field:=vcol, Criteria1:=myarr(i) & ""
If Not Evaluate("=ISREF('" & myarr(i) & "'!A1)") Then
Sheets.Add(after:=Worksheets(Worksheets.Count)).Name = myarr(i) & ""
Else
Sheets(myarr(i) & "").Move after:=Worksheets(Worksheets.Count)
End If
ws.Range("A" & titlerow & ":A" & lr).EntireRow.Copy Sheets(myarr(i) & "").Range("A1")
Sheets(myarr(i) & "").Columns.AutoFit
Next
ws.AutoFilterMode = False
ws.Activate
End Sub
This will do it. Note that this will delete the sheets if they already exist, feel free to tweak if you don't want that to happen. Also, it will trip up if in Column A you have values that Excel won't accept as a sheet name (e.g. "/")
Option Explicit
Sub split_worksheet()
'This will create a new sheet for each unique value in Column A of Sheet1.
'Note: you will need to delete everything besides sheet1.
'Set up looping variables
Dim sheet1 As Worksheet
Set sheet1 = ThisWorkbook.Sheets("Sheet1")
Dim sheet1_rows As Integer
sheet1_rows = sheet1.UsedRange.Rows.Count
Dim sheet1_cols As Integer
sheet1_cols = sheet1.UsedRange.Columns.Count
'Loop through column A, adding sheets as we go
Dim i As Integer, colA_value As String
Dim rng1 As Range, rng2 As Range
Dim sheetDict As Object
Set sheetDict = CreateObject("scripting.dictionary")
For i = 2 To sheet1_rows
colA_value = sheet1.Cells(i, 1).Value
If Not sheetDict.Exists(colA_value) Then
'Delete the sheets if they already exist
on error resume next
thisworkbook.sheets(colA_value).delete
on error goto 0
'Handle blank rows in A
If colA_value = "" Then colA_value = "BLANK"
'create the new sheet
ThisWorkbook.Worksheets.Add().Name = colA_value
'Write the header row
ThisWorkbook.Sheets(colA_value).Range(Cells(1, 1).Address + ":" + Cells(1, sheet1_cols).Address).Value = sheet1.Range(Cells(1, 1).Address + ":" + Cells(1, sheet1_cols).Address).Value
'add target row to our dictionary
sheetDict.Add colA_value, 2
'copy the range from sheet1 to the new sheet
Set rng1 = sheet1.Range(Cells(i, 1).Address + ":" + Cells(i, sheet1_cols).Address)
Set rng2 = ThisWorkbook.Sheets(colA_value).Range(Cells(sheetDict.Item(colA_value), 1).Address + ":" + Cells(sheetDict.Item(colA_value), sheet1_cols).Address)
rng2.Value = rng1.Value
'Add a row to the sheetDict
sheetDict.Item(colA_value) = sheetDict.Item(colA_value) + 1
Else
'copy the range from sheet1 to the new sheet
'Debug.Print sheetDict.Item(colA_value)
Set rng1 = sheet1.Range(Cells(i, 1).Address + ":" + Cells(i, sheet1_cols).Address)
Set rng2 = ThisWorkbook.Sheets(colA_value).Range(Cells(sheetDict.Item(colA_value), 1).Address + ":" + Cells(sheetDict.Item(colA_value), sheet1_cols).Address)
rng2.Value = rng1.Value
'Add a row to the sheetDict
sheetDict.Item(colA_value) = sheetDict.Item(colA_value) + 1
'Debug.Print colA_value, sheetDict.Items(colA_value)
End If 'sheetDict.exists columnA
Next i
'Garbage clean
Set sheet1 = Nothing
Set sheetDict = Nothing
Set rng1 = Nothing
Set rng2 = Nothing
End Sub