I came across the below code when looking for ways to sequentially add sheets using VBA. This code works great and does exactly what I need it to do up until it reaches the 10th worksheet. Once it reaches the 10th sheet ( i.e., "Combined-10" ), it throws an error when attempting to advance to the 11th sheet etc. I'm fairly new to VBA and do not know how to correct this. I'm simply needing help fixing this issue so that the worksheet continues to advance to the next sequential sheet once it reaches sheet number 10. Any help would be much appreciated!
Link to original code:
Adding Sheets With Sequential Names
Adding Sheets With Sequential Names
Option Explicit
Sub GetAvailableSheeName()
Dim sht As Worksheet
Dim temp_sht
Dim sht_name, last_sht As String
Dim shtNumber
Dim temp_counter, loop_i, counter, num As Integer
Const Available_sht As String = "Combined-"
temp_counter = 0
For Each sht In ThisWorkbook.Worksheets
If LCase(Left(sht.name, Len(Available_sht))) = LCase(Available_sht) Then
shtNumber = Split(sht.name, "-")(1)
If IsNumeric(shtNumber) Then
If shtNumber > temp_counter Then
temp_counter = shtNumber
last_sht = sht.name
End If
Else
sht_name = sht.name
End If
Else
sht_name = sht.name
End If
Next sht
If temp_counter = 0 Then
ThisWorkbook.Sheets.Add(After:=Sheets(sht_name)).name = "Combined-1"
Else
ThisWorkbook.Sheets.Add(After:=Sheets(last_sht)).name = "Combined-" & temp_counter + 1
For loop_i = 1 To temp_counter + 1
For Each sht In ThisWorkbook.Worksheets
counter = 0
If LCase("Combined-") & loop_i = LCase(sht.name) Then
counter = 1
Exit For
End If
Next sht
If counter = 0 Then
If loop_i = 1 Then
ThisWorkbook.Sheets.Add(Before:=Sheets(1)).name = "Combined-" & loop_i
Else
num = loop_i - 1
ThisWorkbook.Sheets.Add(After:=Sheets("Combined-" & num)).name = "Combined-" & loop_i
End If
End If
Next loop_i
End If
End Sub
Add Worksheets With Sequential Names
Compact
Sub GetAvailableSheetName()
On Error GoTo ClearError
Dim ws As Worksheet
Dim n As Long
Dim wsName As String
Do
n = n + 1
wsName = "Combined-" & n
Set ws = ThisWorkbook.Worksheets(wsName)
Loop
WorksheetNaming:
On Error Resume Next
ThisWorkbook.Worksheets .Add(After:=ThisWorkbook _
.Sheets(ThisWorkbook.Sheets.Count)).Name = wsName
On Error GoTo 0
Exit Sub
ClearError:
Resume WorksheetNaming
End Sub
Argumented
Sub AddSequentialSheetNameTEST()
AddSequentialSheetName ThisWorkbook, "Combined-"
MsgBox "Added the worksheet '" & ActiveSheet.Name, vbInformation
End Sub
Sub AddSequentialSheetName( _
ByVal wb As Workbook, _
Optional ByVal Prefix As String = "Sheet", _
Optional ByVal Suffix As String = "")
On Error GoTo ClearError
Dim ws As Worksheet
Dim n As Long
Dim wsName As String
Do
n = n + 1
wsName = Prefix & n & Suffix
Set ws = wb.Worksheets(wsName)
Loop
WorksheetNaming:
On Error Resume Next
wb.Worksheets.Add(After:=wb.Sheets(wb.Sheets.Count)).Name = wsName
On Error GoTo 0
Exit Sub
ClearError:
Resume WorksheetNaming
End Sub
Related
I've got a code that generates a workbook by copying and moving selected worksheets into a new workbook.
The first page of this new workbook is a summary page. On this i want to pull data from the subsequent worksheets by using the range.value method.
However can I use this when referencing the worksheet location for example
Dim wb As Workbook, wbAll As Workbook
Dim ws As Worksheet
Set wbAll = Workbooks.Add
On Error Resume Next
For t = 1 To 100
Set wb = Workbooks("Book" & t)
For Each ws In wb.Sheets
ws.Move after:=wbAll.Sheets(Sheets.Count)
Next
Next
Workbooks("Book" & t).Activate
ActiveWorkbook.Sheets("Sheet1").Select
'compile worksheets into list
Dim wss As Worksheet
Dim x As Integer
On Error Resume Next
x = 17
Sheets("Sheet1").Range("c17:E46").ClearContents
For Each wss In ActiveWorkbook.Worksheets
If wss.Name <> "Sheet1" Then
Sheets("Sheet1").Cells(x, 3) = wss.Name
x = x + 1
End If
Next wss
'COMPILE COSTS
ActiveWorkbook.Sheet1.Range("C17").Value = ActiveWorkbook.Worksheet(2).Range("Q118").Value
ActiveWorkbook.Sheet1.Range("C18").Value = ActiveWorkbook.Worksheet(3).Range("Q118").Value
.
.
ActiveWorkbook.Sheet1.Range("C45").Value = ActiveWorkbook.Worksheet(30).Range("Q118").Value
ActiveWorkbook.Sheet1.Range("C46").Value = ActiveWorkbook.Worksheet(31).Range("Q118").Value
'Compile WBS
ActiveWorkbook.Sheet1.Range("D17").Value = ActiveWorkbook.Worksheet(2).Range("D10").Value
ActiveWorkbook.Sheet1.Range("D18").Value = ActiveWorkbook.Worksheet(3).Range("D10").Value
.
.
ActiveWorkbook.Sheet1.Range("D45").Value = ActiveWorkbook.Worksheet(30).Range("D10").Value
ActiveWorkbook.Sheet1.Range("D46").Value = ActiveWorkbook.Worksheet(31).Range("D10").Value
'Week Number name
ActiveWorkbook.Sheet1.Range("C10").Value = ActiveWorkbook.Worksheet(2).Range("D4").Value
'Supplier Name
ActiveWorkbook.Sheet1.Range("C12").Value = ActiveWorkbook.Worksheet(2).Range("D5").Value
This however gives me an error message of object defined error
This may help:
EDIT: updated to show using links instead of copying the values from the sheet.
Sub Tester()
Dim wb As Workbook, wbAll As Workbook
Dim ws As Worksheet
Dim wss As Worksheet
Dim x As Integer, wsSummary, t As Long
Set wbAll = Workbooks.Add
For t = 1 To 100
Set wb = Nothing
On Error Resume Next 'ignore any error
Set wb = Workbooks("Book" & t)
On Error GoTo 0 'cancel OERN as soon as possible
If Not wb Is Nothing Then
For Each ws In wb.Sheets
ws.Move after:=wbAll.Sheets(wbAll.Sheets.Count)
Next
End If
Next
'Workbooks("Book" & t).Activate 'not sure what this is for?
'ActiveWorkbook.Sheets("Sheet1").Select
'compile worksheets into list
x = 17
Set wsSummary = wbAll.Sheets("Sheet1")
wsSummary.Range("C17:E46").ClearContents
For Each wss In wbAll.Worksheets
If wss.Name <> wsSummary.Name Then
With wsSummary.Rows(x)
'.Cells(3).Value = wss.Name
InsertLink .Cells(5), wss.Range("A1"), "=SheetName({1})"
'.Cells(4).Value = wss.Range("Q118").Value
InsertLink .Cells(4), wss.Range("Q118") 'create a link
'.Cells(5).Value = wss.Range("D10").Value
InsertLink .Cells(5), wss.Range("D10")
'etc etc
End With
x = x + 1
End If
Next wss
End Sub
'UDF to return the sheet name
Function SheetName(c As Range)
Application.Volatile
SheetName = c.Parent.Name
End Function
'Insert a worksheet formula into a cell (rngDest), where the precedents
' are either a single cell/range or an array of cells/ranges (SourceRange)
' sTemplate is an optional string template for the formula
' eg. "=SUM({1},{2})" where {1} and {2} are ranges in SourceRange
' Empty template defaults to "={1}"
'Useage:
' InsertLink sht1.Range("A1"), Array(sht1.Range("B1"), sht1.Range("C1")), "=SUM({1},{2})"
Sub InsertLink(rngDest As Range, SourceRange As Variant, Optional sTemplate As String)
Dim i As Long, sAddress As String, arrTmp As Variant
If sTemplate = "" Then sTemplate = "={1}" 'default is a simple linking formula
'got a single range, or an array of ranges?
If TypeName(SourceRange) = "Range" Then
arrTmp = Array(SourceRange) 'make an array from the single range
Else
arrTmp = SourceRange 'use as-is
End If
'loop over the input range(s) and build the formula
For i = LBound(arrTmp) To UBound(arrTmp)
sAddress = ""
If rngDest.Parent.Name <> arrTmp(i).Parent.Name Then
sAddress = "'" & arrTmp(i).Parent.Name & "'!"
End If
sAddress = sAddress & arrTmp(i).Address(False, False)
sTemplate = Replace(sTemplate, "{" & CStr(i + 1) & "}", sAddress)
Next i
rngDest.Formula = sTemplate 'assign the formula
End Sub
Regarding the last query:
VBA Excel add new sheet with number based on the previous sheet created
I would like to duplicate the existing sheet and then add it under the incremented number, although on the same basis as mentioned in my previous query. I want to have the sheet number based on the last sheet number created.
If I take into account for example this code:
Public Sub CreateSheet()
Dim wb As Workbook: Set wb = ActiveWorkbook
Dim ws As Worksheet
Dim startNmae As String: startName = "Area Map "
Dim counter As Integer: counter = 1
For Each ws In wb.Sheets
If Left(ws.Name, Len(startName)) = startName Then
counter = counter + 1
End If
Next was
Set ws = wb.Sheets.Copy
startName = startName & counter
ws.Name = startName
End Sub
I am getting an error: Expected function or variable
with debugger showing the line:
Set ws = wb.Sheets.Copy
The other approaches also weren't working
Sub Newsheets()
Dim wb As Workbook: Set wb = ActiveWorkbook
Dim ws As Worksheet
Dim startName As String: startName = "Area Map "
Dim counter As Integer: counter = 1
For Each ws In wb.Sheets
If Left(ws.Name, Len(startName)) = startName Then
counter = counter + 1
End If
Next was
Set ws = ThisWorkbook.Sheets("Area Map" & counter)
With was
.Copy After:=Sheets(Sheets.Count)
startName = startName & counter
.Name = startName
End With
End Sub
Now I am getting: Subscript out of range, for the following line
Set ws = ThisWorkbook.Sheets("Area Map" & counter)
The next option wasn't successful either:
Sub ConsecutiveNumberSheets2()
Dim ws As Worksheet, wb As Workbook
Dim i As Long
Dim startName As String: startName = "Area Map "
Dim counter As Integer: counter = 1
Set wb = ThisWorkbook
Set ws = wb.Sheets("Area Map 1")
For Each ws In wb.Sheets
If Left(ws.Name, Len(startName)) = startName Then
counter = counter + 1
End If
Next was
For i = 1 To Sheets.Count - (Sheets.Count - 1)
With Sheets("Area Map 1")
.Copy After:=Sheets(Sheets.Count)
ActiveSheet.Name = "Area Map" & counter + 1
.Select
End With
Next i
End Sub
I need to have the sheet copied under the incremented number. I would like to base the incrementation on the last existing number of the sheet. Is it possible?
One of the solution is base on total number of sheets with similar or the same name occurring throughout our workbook.
The solution can be found here:
https://www.extendoffice.com/documents/excel/5098-excel-vba-count-sheets-with-specific-name.html
If we determine the number of sheets with specific name, then copying them only once a few times won't be a problem.
The final code could look as follows:
Sub Consecutivesheetduplicate()
Dim wsr as Worksheet
Dim I As Long
Dim xCount As Integer
Set wsr = ThisWorkbook.Sheets("Area Map 1")
For I = 1 To ActiveWorkbook.Sheets.Count
If InStr(1, Sheets(I).Name, "Area") > 0 Then xCount = xCount + 1
Next
For I = 1 To Sheets.Count - (Sheets.Count - 1)
On Error Resume Next
With Sheets("Area Map 1")
.Copy After:=ActiveWorkbook.Sheets(wsr.Index + xCount + I)
ActiveSheet.Name = "Area Map " & xCount + 1
.Select
End With
Next I
End Sub
Hi everyone! I'm trying to write a method in VBA to keep 2 worksheets and delete others at the same time.
I already did the one that will keep one worksheet and delete others like this:
Sub delete_all_pages_except_main()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
Application.DisplayAlerts = False
If ws.Name <> "Home Page" Then
ws.Delete
End If
Next ws
End Sub
And I try to write it like this
If (ws.Name <> "Home Page" Or ws.Name <> "Data")
But VBA would accept it.
Can you guys help? Thank you.
This should do
Sub delete_all_pages_except_main()
Dim ws As Worksheet
Dim arr As Variant
Dim boo As Boolean
Application.DisplayAlerts = False
arr = Array("Home Page", "Data")
For Each ws In ThisWorkbook.Worksheets
boo = NoDel(ws.Name, arr)
If boo <> True Then ws.Delete
Next ws
Application.DisplayAlerts = True
End Sub
Function NoDel(ws As String, warr As Variant) As Boolean
NoDel = False
For i = LBound(warr, 1) To UBound(warr, 1)
If warr(i) = ws Then NoDel = True
Next i
End Function
Delete Sheets With Exceptions
Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: In a specified workbook, writes all the sheet names '
' not specified in an Exceptions array to a Result array, and '
' using the Result array deletes all the sheets in one go. '
' Remarks: This solution applies to worksheets and chartsheets. '
' Since there is no Sheet object, the For Next loop (instead '
' of the For Each Next loop) and the Object type have '
' to be used. '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub deleteSheets(Book As Workbook, Exceptions As Variant)
' Program
Dim SheetsCount As Long: SheetsCount = Book.Sheets.Count
Dim Result As Variant: ReDim Result(SheetsCount)
Dim sh As Object, i As Long, j As Long
j = -1
For i = 1 To SheetsCount: GoSub checkName: Next i
If j = -1 Then GoTo NothingToDelete
If j = SheetsCount - 1 Then GoTo NoExceptions
GoSub deleteSheetsInOneGo
MsgBox "Deleted '" & j + 1 & "' sheets.", vbInformation, "Success"
Exit Sub
' Subroutines
checkName:
Set sh = Book.Sheets(i)
If IsError(Application.Match(sh.Name, Exceptions, 0)) Then
j = j + 1
Result(j) = sh.Name
End If
Return
deleteSheetsInOneGo:
ReDim Preserve Result(j)
Application.DisplayAlerts = False
Book.Sheets(Result).Delete
Application.DisplayAlerts = True
Return
' Labels
NothingToDelete:
MsgBox "Sheets already deleted.", vbCritical, "Nothing to Delete"
Exit Sub
NoExceptions:
MsgBox "Cannot delete all sheets.", vbCritical, "No Exceptions"
Exit Sub
End Sub
' Usage Example
Sub runDeleteSheets()
Dim SheetNames As Variant: SheetNames = Array("Home Page", "Data")
deleteSheets ThisWorkbook, SheetNames
End Sub
Good morning,
I am using the following code:
Sub CABsheet()
Dim i As Long
Dim xNumber As Long
Dim xName As String
Dim ws As Worksheet
Application.ScreenUpdating = False
Set ws = Sheets("CAB1")
xNumber = Sheets("NIM & BADGER").Range("R27").Value
For i = 1 To Number
ws.Copy After:=ActiveWorkbook.Sheets(ws.Index + i - 1)
ActiveSheet.Name = "CAB" & i + 1
Next
ws.Activate
Application.ScreenUpdating = True
End Sub
but I am getting an error saying, that the sheet under this name already exists.
when I use a bit changed code like this:
Sub CABsheet()
Dim i As Long
Dim xNumber As Long
Dim xName As String
Dim ws As Worksheet
Application.ScreenUpdating = False
Set ws = Sheets("CAB1")
xNumber = Sheets("NIM & BADGER").Range("R27").Value
For i = 2 To Number
ws.Copy After:=ActiveWorkbook.Sheets(ws.Index + (i - 2))
ActiveSheet.Name = "CAB" & (i + 1) + 2
Next
ws.Activate
Application.ScreenUpdating = True
End Sub
then an error is gone, and everything seems to be alright but...
... i am getting numeration from CAB5 onwards instead of CAB 2
If I change a bit of my code again...
For i = 2 To xNumber
ws.Copy After:=ActiveWorkbook.Sheets(ws.Index + (i - 1))
ActiveSheet.Name = "CAB" & i + 2
Next
then order is wrong.
The tabs are from CAB4 onwards.
I need them from CAB2 onwards.
I can't remove +2 because the debugger shows me an error, that the name already been taken.
What can I fix in this code?
In your very first code example you
Dim xNumber As Long
you set a value for it
xNumber = Sheets("NIM & BADGER").Range("R27").Value
and then you use the variable Number instead of xNumber in your loop:
For i = 2 To Number
The variable Number is not declared nor initialized with a value and therefore it is 0.
So this cannot work. Make sure you use Option Explicit so you get notified if you use a worng variable name that was not declared.
I also recommend not to use ActiveSheet
Option Explicit
Public Sub CABsheet()
Application.ScreenUpdating = False
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("CAB1")
Dim xNumber As Long
xNumber = ThisWorkbook.Worksheets("NIM & BADGER").Range("R27").Value
Dim i As Long
For i = 1 To xNumber
ws.Copy After:=ThisWorkbook.Sheets(ws.Index + i - 1)
ThisWorkbook.Sheets(ws.Index + i).Name = "CAB" & i + 1
Next
ws.Activate
Application.ScreenUpdating = True
End Sub
Before running the code:
After running the code:
You could also built in a test if the worksheet already exists and ask the user if it should be deleted:
Option Explicit
Public Sub CABsheet()
Application.ScreenUpdating = False
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("CAB1")
Dim xNumber As Long
xNumber = 10
Dim i As Long
For i = 1 To xNumber
ws.Copy After:=ThisWorkbook.Sheets(ws.Index + i - 1)
If WorksheetExists("CAB" & i + 1) Then
If MsgBox("Worksheet '" & "CAB" & i + 1 & "' already exists. Do you want to delete it?", vbExclamation + vbYesNo) = vbYes Then
Application.DisplayAlerts = False
ThisWorkbook.Sheets("CAB" & i + 1).Delete
Application.DisplayAlerts = True
ThisWorkbook.Sheets(ws.Index + i).Name = "CAB" & i + 1
End If
Else
ThisWorkbook.Sheets(ws.Index + i).Name = "CAB" & i + 1
End If
Next
ws.Activate
Application.ScreenUpdating = True
End Sub
Public Function WorksheetExists(ByVal WorksheetName As String, Optional ByVal InWorkbook As Workbook) As Boolean
If InWorkbook Is Nothing Then
Set InWorkbook = ThisWorkbook
End If
On Error Resume Next
Dim ws As Worksheet
Set ws = InWorkbook.Worksheets(WorksheetName)
On Error GoTo 0
WorksheetExists = Not ws Is Nothing
End Function
I need to write a macro that adds a new sheet when executed. The sheet name will be "Combined-n" where n is an integer. I want it to try add a new sheet named "Combined-1". However, if the sheet "Combined-1" already exists (since this macro can be executed multiple times), I want it to add a sheet called "Combined-2" and so on. I tried a few different things including the code below, but when I execute it nothing happens.
Dim i As Integer
Dim WS As Worksheet
For Each WS In ThisWorkbook.Worksheets
WS.Activate
For i = 1 To Worksheets.Count
If WS.Name = "Combined-" & i Then
Sheets.Add(Before:=Sheets("Sheet1")).Name = "Combined-" & i + 1
End If
Next i
Next WS
I also tried:
Dim i As Integer
For i = 1 To Worksheets.Count
If Worksheets(i).Name = "Combined-" & i Then
Sheets.Add(Before:=Sheets("Sheet1")).Name = "Combined-" & i + 1
End If
Next i
Write a function whose only job is to return the name of the next "Combined-N" sheet. I'd do this by counting the number of sheets that have a name that starts with "Combined-", and adding 1 to that number, and then incrementing until "Combined-" concatenated with that number is a sheet name that doesn't already exist.
So, I'd have a GetNextCombinedSheetName function to do this, and a SheetNameExists function to determine whether a given sheet name exists in an optionally-specified Workbook's Worksheets collection.
Something like this:
Public Function GetNextCombinedSheetName() As String
Const namePrefix As String = "Combined-"
Dim currentcount As Long
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
If Left(ws.Name, Len(namePrefix)) = namePrefix Then
currentCount = currentCount + 1
End If
Next
Dim nextName As String
Do 'ensure the name doesn't already exist - increment if it does:
nextName = namePrefix & currentCount + 1
Loop While SheetNameExists(nextName)
GetNextCombinedSheetName = nextName
End Function
Private Function SheetNameExists(ByVal sheetName As String, Optional ByVal wb As Workbook = Nothing) As Boolean
If wb Is Nothing Then Set wb = ThisWorkbook
Dim ws As Worksheet
On Error Resume Next ' swallow index out of bounds error 9
Set ws = wb.Worksheets(sheetName)
On Error GoTo 0
SheetNameExists = Not ws Is Nothing
End Function
With that, you can add a new sheet and just name it:
Dim newSheet As Worksheet
Set newSheet = ThisWorkbook.Worksheets.Add
newSheet.Name = GetNextCombinedSheetName
Note how every Worksheets member call (or Sheets - but why are you using the two interchangeably and inconsistently?) is properly qualified with a Workbook object: your code appears to have several implicit ActiveWorkbook references, and this only works because the ActiveWorkbook happens to be the host ThisWorkbook document - it may not always be the case (especially as you learn to stop Activate-ing and Select-ing things), and you don't want your code to assume it is: life is much simpler when we systematically qualify workbook and worksheet member calls.
#chrisphils26 - you can try below code also
Option Explicit
Sub GetAvailableSheeName()
Dim sht As Worksheet
Dim temp_sht
Dim sht_name, last_sht As String
Dim shtNumber
Dim temp_counter, loop_i, counter, num As Integer
Const Available_sht As String = "Combined-"
temp_counter = 0
For Each sht In ThisWorkbook.Worksheets
If LCase(Left(sht.name, Len(Available_sht))) = LCase(Available_sht) Then
shtNumber = Split(sht.name, "-")(1)
If IsNumeric(shtNumber) Then
If shtNumber > temp_counter Then
temp_counter = shtNumber
last_sht = sht.name
End If
Else
sht_name = sht.name
End If
Else
sht_name = sht.name
End If
Next sht
If temp_counter = 0 Then
ThisWorkbook.Sheets.Add(After:=Sheets(sht_name)).name = "Combined-1"
Else
ThisWorkbook.Sheets.Add(After:=Sheets(last_sht)).name = "Combined-" & temp_counter + 1
For loop_i = 1 To temp_counter + 1
For Each sht In ThisWorkbook.Worksheets
counter = 0
If LCase("Combined-") & loop_i = LCase(sht.name) Then
counter = 1
Exit For
End If
Next sht
If counter = 0 Then
If loop_i = 1 Then
ThisWorkbook.Sheets.Add(Before:=Sheets(1)).name = "Combined-" & loop_i
Else
num = loop_i - 1
ThisWorkbook.Sheets.Add(After:=Sheets("Combined-" & num)).name = "Combined-" & loop_i
End If
End If
Next loop_i
End If
End Sub