153
Dim wkbkdestination As Workbook
Dim destsheet As Worksheet

For Each ThisWorkSheet In wkbkorigin.Worksheets 
    'this throws subscript out of range if there is not a sheet in the destination 
    'workbook that has the same name as the current sheet in the origin workbook.
    Set destsheet = wkbkdestination.Worksheets(ThisWorkSheet.Name) 
Next

Basically I loop through all sheets in the origin workbook then set destsheet in the destination workbook to the sheet with the same name as the currently iterated one in the origin workbook.

How can I test if that sheet exists? Something like:

If wkbkdestination.Worksheets(ThisWorkSheet.Name) Then 
BigBen
  • 46,229
  • 7
  • 24
  • 40
yse
  • 1,541
  • 2
  • 10
  • 4

24 Answers24

239

Some folk dislike this approach because of an "inappropriate" use of error handling, but I think it's considered acceptable in VBA... An alternative approach is to loop though all the sheets until you find a match.

Function WorksheetExists(shtName As String, Optional wb As Workbook) As Boolean
    Dim sht As Worksheet

    If wb Is Nothing Then Set wb = ThisWorkbook
    On Error Resume Next
    Set sht = wb.Sheets(shtName)
    On Error GoTo 0
    WorksheetExists = Not sht Is Nothing
End Function
darcyy
  • 5,236
  • 5
  • 28
  • 41
Tim Williams
  • 154,628
  • 8
  • 97
  • 125
  • 7
    Entirely approriate use IMO. It's a trap for a thing that is posited as existing and doesn't and has a long history - cf perl strict, STAE etc. Upvoted – Wudang Oct 18 '11 at 08:37
  • 20
    One should probably use `ActiveWorkbook` instead of `ThisWorkbook`. The latter refers to the workbook that contains the macro code, which might be different from the workbook than one wants to test. I guess `ActiveWorkbook` would be useful for most cases (contrived situations are always available, though). – sancho.s ReinstateMonicaCellio Sep 06 '14 at 18:49
  • Noob at vba but can't find why this function drives the code exec to error 9. Found the answer here : http://stackoverflow.com/a/11459834/461212 – hornetbzz Nov 18 '14 at 21:25
  • I don't get `SheetExists = Not sht Is Nothing` XD What does that mean? The function is returning the opposite of sheet is nothing?? – findwindow Oct 15 '15 at 20:48
  • 4
    `sht Is Nothing` will be `True` if there's no sheet with that name, but we want to return `True` if there *is* a sheet with that name, hence the Not. It's a little easier (but not valid) if you re-arrange a bit to `SheetExists = sht Is Not Nothing` – Tim Williams Oct 15 '15 at 21:12
  • <3 @TimWilliams That makes perfect sense. Now I just need to figure out why I can't get it to work XD – findwindow Oct 15 '15 at 21:30
  • 4
    Good to note that if you run this code in your personal macro workbook, change from `If wb Is Nothing Then Set wb = ThisWorkbook` to `If wb Is Nothing Then Set wb = ActiveWorkbook` – Henrik K Dec 31 '15 at 08:44
  • 2
    This is a highly-efficient approach (see my comments about bench marks under Rory's answer below), so who cares what the detractors think. Note (as of now) you have zero down votes. – rory.ap Mar 15 '16 at 12:15
  • 1
    In the interest of spreading high speed code, you can make this 85+% faster by changing `wb Is Nothing` to `IsMissing(wb)`. – Taylor Alex Raine Jun 12 '18 at 18:41
  • 1
    True that's slightly faster but only noticeable if you need to check >10k or 100k sheets... – Tim Williams Jun 12 '18 at 20:32
  • 2
    @TimWilliams You should either change to `Dim sht As Object` or name the function `WorksheetExists(…)` and use `Set sht = wb.Workheets(shtName)` otherwise it returns `False` on checking for eg. chart sheets that actually exist. Eg. `SheetExists("Chart1")` returns `False` even if a chart sheet named `Chart1` exists. • `Sheets != Worksheets` – Pᴇʜ Nov 07 '18 at 09:46
  • I can't figure how to use this function on an external sourced workbook... I've tried to execute it as `=WorksheetExists(A1;"C:\path\workbook.xlsx")` with `A1` containing my `SheetName` but I get an error... Thanks for helping. – Jeanjean Jan 09 '23 at 19:54
  • 1
    It will not work if the other workbook is not open. – Tim Williams Jan 09 '23 at 20:03
  • Thanks. That’s exactly what I’m trying to do. Any idea on how to do? I tried [this](https://stackoverflow.com/questions/71796894/check-if-sheet-exists-in-closed-workbook) but it seems ExecuteExcel4Macros has been disabled by default… I’m really struggling on that one. – Jeanjean Jan 09 '23 at 20:19
127

If you are specifically interested in worksheets only, you can use a simple Evaluate call:

Function WorksheetExists(sName As String) As Boolean
    WorksheetExists = Evaluate("ISREF('" & sName & "'!A1)")
End Function
Rory
  • 32,730
  • 5
  • 32
  • 35
  • 2
    One simple evaluation. It doesn't even need a separate function IMO. Well played! – bp_ Feb 08 '16 at 13:56
  • 1
    Really simple and efficient code and a ton of thanks for helping me discover the Evaluate command. Respect! – Cornel Mar 03 '16 at 19:50
  • 18
    @Rory I ran some benchmark tests on this vs. Tim Williams' answer. Over 500,000 loops, yours took 22 seconds and Tim's took <1. – rory.ap Mar 15 '16 at 12:10
  • 1
    @Cornel -- See my comment. Be careful when you bandy around the word "efficient". – rory.ap Mar 15 '16 at 12:11
  • 27
    @roryap - if you need to run this 500,000 times, you need to rethink your entire approach. ;) – Rory Mar 15 '16 at 14:13
  • @Rory -- totally agree. I just thought it was interesting and something for posterity. – rory.ap Mar 15 '16 at 14:15
  • 11
    @roryap - however, using several slow methods will start piling up seconds. I would say this is extremely valuable information, as Excel "applications" start to rack up seconds pretty easily with various Range methods etc. – tedcurrent Mar 16 '16 at 14:41
  • 5
    @roryap - that information is valuable to the conversation in what way? I'm simply stating that scattering inefficient methods around your code will make the application slow as a whole. you testing this 500k times is awesome and I thank you for doing it, 22 seconds is not great. (I agree with you) – tedcurrent Mar 16 '16 at 15:18
  • 8
    Even if it's slower, it looks like a much cleaner solution than the accepted answer. +1 from me. – Sascha L. Sep 08 '17 at 09:46
  • I like this code, but I also appreciate knowing which method is faster. For what I am doing today, marginally slower is fine, for other applications I'm fighting for every millisecond. – OSUZorba Feb 05 '21 at 14:54
72

You don't need error handling in order to accomplish this. All you have to do is iterate over all of the Worksheets and check if the specified name exists:

Dim exists As Boolean

For i = 1 To Worksheets.Count
    If Worksheets(i).Name = "MySheet" Then
        exists = True
    End If
Next i

If Not exists Then
    Worksheets.Add.Name = "MySheet"
End If
ke1v3y
  • 47
  • 4
fbonetti
  • 6,652
  • 3
  • 34
  • 32
  • 1
    Careful, sheet names are not case-sensitive: https://www.howtoexcel.org/how-to-check-if-a-worksheet-exists-using-vba/ – LePatay Jun 14 '22 at 08:54
26

I wrote this one:

Function sheetExist(sSheet As String) As Boolean
On Error Resume Next
sheetExist = (ActiveWorkbook.Sheets(sSheet).Index > 0)
End Function
AOBR
  • 269
  • 3
  • 5
  • 1
    Great function! Not only is it fast, it's also the most concise. – ChrisB Jun 07 '18 at 22:45
  • I beleive this is the answer that corresponds to the question the most – Juan Joya Dec 03 '18 at 14:59
  • 2
    I like this one. Note that it relies on the fact that the default value for sheetExist will be False since it's a Boolean function. The assignment statement doesn't actually assign a False value to sheetExist if the sheet doesn't exist, it just errors out and leaves the default value in place. If you want to, you can rely on the fact that any non-zero value assigned to a Boolean variable will give a True result and leave out the > 0 comparison, like so: `sheetExist = ActiveWorkbook.Sheets(sSheet).Index` – oddacorn Sep 04 '19 at 19:59
23

As checking for members of a collection is a general problem, here is an abstracted version of @Tim's answer:

Function Contains(objCollection As Object, strName as String) As Boolean
    Dim o as Object
    On Error Resume Next
    set o = objCollection(strName)
    Contains = (Err.Number = 0)
    Err.Clear
 End Function

This function can be used with any collection like object (Shapes, Range, Names, Workbooks, etc.).

To check for the existence of a sheet, use If Contains(Sheets, "SheetName") ...

shA.t
  • 16,580
  • 5
  • 54
  • 111
Peter Albert
  • 16,917
  • 5
  • 64
  • 88
  • 5
    This doesn't catch primitive types in Collections as an error will be raised by the `Set` keyword. I found that rather than using `Set`, asking for the `TypeName` of the member of the collection works for all cases, i.e. `TypeName objCollection(strName)` – citizenkong Aug 04 '14 at 09:59
  • 2
    @Peter: Best to add something to clear the error that will get raised in the case of non existance before the funciton terminates - either an err.clear or On Error Resume Next. Otherwise the error handling in the calling procedure could be inadvertantly triggerred in cases like the following. `Sub Test() On Error GoTo errhandler Debug.Print Contains(Workbooks, "SomeBookThatIsNotOpen") errhandler: If Err.Number <> 0 Then Stop End Sub` – jeffreyweir May 28 '15 at 22:56
18

Corrected: Without error-handling:

Function CheckIfSheetExists(SheetName As String) As Boolean
      CheckIfSheetExists = False
      For Each WS In Worksheets
        If SheetName = WS.name Then
          CheckIfSheetExists = True
          Exit Function
        End If
      Next WS
End Function
Shai Alon
  • 969
  • 13
  • 21
15

In case anyone wants to avoid VBA and test if a worksheet exists purely within a cell formula, it is possible using the ISREF and INDIRECT functions:

=ISREF(INDIRECT("SheetName!A1"))

This will return TRUE if the workbook contains a sheet called SheetName and FALSE otherwise.

VirtualMichael
  • 719
  • 9
  • 18
7

Compact wsExists function (without reliance on Error Handling!)

Here's a short & simple function that doesn't rely on error handling to determine whether a worksheet exists (and is properly declared to work in any situation!)

Function wsExists(wsName As String) As Boolean
    Dim ws: For Each ws In Sheets
    wsExists = (wsName = ws.Name): If wsExists Then Exit Function
    Next ws
End Function

Example Usage:

The following example adds a new worksheet named myNewSheet, if it doesn't already exist:

If Not wsExists("myNewSheet") Then Sheets.Add.Name = "myNewSheet"

More Information:

ashleedawg
  • 20,365
  • 9
  • 72
  • 105
5

My solution looks much like Tims but also works in case of non-worksheet sheets - charts

Public Function SheetExists(strSheetName As String, Optional wbWorkbook As Workbook) As Boolean
    If wbWorkbook Is Nothing Then Set wbWorkbook = ActiveWorkbook 'or ThisWorkbook - whichever appropriate
    Dim obj As Object
    On Error GoTo HandleError
    Set obj = wbWorkbook.Sheets(strSheetName)
    SheetExists = True
    Exit Function
HandleError:
    SheetExists = False
End Function

.

uildriks
  • 51
  • 1
  • 1
4

Many years late, but I just needed to do this and didn't like any of the solutions posted... So I made one up, all thanks to the magic of (SpongeBob rainbow hands gesture) "Evaluate()"!

Evaluate("IsError(" & vSheetName & "!1:1)")

Returns TRUE if Sheet does NOT exist; FALSE if sheet DOES exist. You can substitute whatever range you like for "1:1", but I advise against using a single cell, cuz if it contains an error (eg, #N/A), it will return True.

X37V
  • 49
  • 1
  • I see 2 bugs in the code: (1) if the sheet exists, there's Error 13 because of `1:1` (2) if the sheet name contains a space and exists, the code returns False. To avoid the #N/A problem, I use the CELL function. This works for me: `Evaluate("IsError(Cell(""col"",'" + vSheetName + "'!A1))")` and here to exit a sub if the sheet doesn't exist: `If Evaluate("IsError(Cell(""col"",'" + vSheetName + "'!A1))") Then Exit Sub` – Sandra Rossi Feb 11 '21 at 14:10
4

Short and clean:

Function IsSheet(n$) As Boolean
    IsSheet = Not IsError(Evaluate("'" & n & "'!a1"))
End Function
Roy Latham
  • 343
  • 5
  • 8
Excel Hero
  • 14,253
  • 4
  • 33
  • 40
3

Put the test in a function and you will be able to reuse it and you have better code readability.

Do NOT use the "On Error Resume Next" since it may conflict with other part of your code.

Sub DoesTheSheetExists()
    If SheetExist("SheetName") Then
        Debug.Print "The Sheet Exists"
    Else
        Debug.Print "The Sheet Does NOT Exists"
    End If
End Sub

Function SheetExist(strSheetName As String) As Boolean
    Dim i As Integer

    For i = 1 To Worksheets.Count
        If Worksheets(i).Name = strSheetName Then
            SheetExist = True
            Exit Function
        End If
    Next i
End Function
Martin Carlsson
  • 461
  • 2
  • 6
  • 18
2
Public Function WorkSheetExists(ByVal strName As String) As Boolean
   On Error Resume Next
   WorkSheetExists = Not Worksheets(strName) Is Nothing
End Function

sub test_sheet()

 If Not WorkSheetExists("SheetName") Then
 MsgBox "Not available"
Else MsgBox "Available"
End If

End Sub
M1NT
  • 386
  • 1
  • 4
  • 13
2

Why not just use a small loop to determine whether the named worksheet exists? Say if you were looking for a Worksheet named "Sheet1" in the currently opened workbook.

Dim wb as Workbook
Dim ws as Worksheet

Set wb = ActiveWorkbook

For Each ws in wb.Worksheets

    if ws.Name = "Sheet1" then
        'Do something here
    End if

Next
ScottMcC
  • 4,094
  • 1
  • 27
  • 35
2
    For Each Sheet In Worksheets
    If UCase(Sheet.Name) = "TEMP" Then
    'Your Code when the match is True
        Application.DisplayAlerts = False
        Sheet.Delete
        Application.DisplayAlerts = True
    '-----------------------------------
    End If
Next Sheet
Shrikant
  • 523
  • 4
  • 15
2

If you are a fan of WorksheetFunction. or you work from a non-English country with a non-English Excel this is a good solution, that works:

WorksheetFunction.IsErr(Evaluate("'" & wsName & "'!A1"))

Or in a function like this:

Function WorksheetExists(sName As String) As Boolean
    WorksheetExists = Not WorksheetFunction.IsErr(Evaluate("'" & sName & "'!A1"))
End Function
Vityata
  • 42,633
  • 8
  • 55
  • 100
1

Without any doubt that the above function can work, I just ended up with the following code which works pretty well:

Sub Sheet_exist ()
On Error Resume Next
If Sheets("" & Range("Sheet_Name") & "") Is Nothing Then
    MsgBox "doesnt exist"
Else
    MsgBox "exist"
End if
End sub

Note: Sheets_Name is where I ask the user to input the name, so this might not be the same for you.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
MAx Segura
  • 15
  • 4
1

Change "Data" to whatever sheet name you're testing for...

On Error Resume Next 

Set DataSheet = Sheets("Data")

If DataSheet Is Nothing Then

     Sheets.Add(after:=ActiveSheet).Name = "Data"
     ''or whatever alternate code you want to execute''
End If

On Error GoTo 0
Dan Lowe
  • 51,713
  • 20
  • 123
  • 112
gth826a
  • 111
  • 1
  • 4
0

I did another thing: delete a sheet only if it's exists - not to get an error if it doesn't:

Excel.DisplayAlerts = False 
Dim WS
For Each WS In Excel.Worksheets
    If WS.name = "Sheet2" Then
        Excel.sheets("Sheet2").Delete
        Exit For
    End If
Next
Excel.DisplayAlerts = True
Shai Alon
  • 969
  • 13
  • 21
0

I use this function to check and return a new sheet name if needed. WSname is the desired worksheet name and WBCur is the workbook you would like to check in. I use this because there is no need for error handling and can call it whenever i am creating a new worksheet.

Public Function CheckNewWorksheetName(WSName As String, WBCur As Workbook) 'Will return New Name if needed
    Dim NewWSNum As Long, A As Integer, B As Integer, WorksheetFound As Boolean
    NewWSNum = 1
    WorksheetFound = False
    For A = 1 To WBCur.Worksheets.Count
        If WBCur.Worksheets(A).Name = WSName Then
            A = WBCur.Worksheets.Count
            WorksheetFound = True
        End If
    Next A
    
    If WorksheetFound = False Then
        CheckNewWorksheetName = WSName
    Else
        Do While WorksheetFound = True
            WorksheetFound = False
            For B = 1 To WBCur.Worksheets.Count
                If WBCur.Worksheets(B).Name = WSName & "_" & NewWSNum Then
                    B = WBCur.Worksheets.Count
                    WorksheetFound = True
                    NewWSNum = NewWSNum + 1
                End If
            Next B
        Loop
        CheckNewWorksheetName = WSName & "_" & NewWSNum
    End If
End Function
0

No need to loop or use a function, that I can see?

If wkbkdestination.Worksheets(ThisWorkSheet.Name).Name = ThisWorksheet.Name Then

'Do stuff

Else

'Go to end of loop

End If

Geoff Kendall
  • 1,307
  • 12
  • 13
-1

I came up with an easy way to do it, but I didn't create a new sub for it. Instead, I just "ran a check" within the sub I was working on. Assuming the sheet name we're looking for is "Sheet_Exist" and we just want to activate it if found:

Dim SheetCounter As Integer

SheetCounter = 1

Do Until Sheets(SheetCounter).Name = "Sheet_Exist" Or SheetCounter = Sheets.Count + 1
 SheetCounter = SheetCounter +1
Loop
If SheetCounter < Sheets.Count + 1 Then
 Sheets("Sheet_Exist").Activate
Else
 MsgBox("Worksheet ""Sheet_Exist"" was NOT found")
End If

I also added a pop-up for when the sheet doesn't exist.

imjordy23
  • 1
  • 1
-1

I know it is an old post, but here is another simple solution that is fast.

Public Function worksheetExists(ByVal wb As Workbook, ByVal sheetNameStr As String) As Boolean

On Error Resume Next
worksheetExists = (wb.Worksheets(sheetNameStr).Name <> "")
Err.Clear: On Error GoTo 0

End Function
Guest
  • 430
  • 2
  • 4
-5

I actually had a simple way to check if the sheet exists and then execute some instruction:

In my case I wanted to delete the sheet and then recreated the same sheet with the same name but the code was interrupted if the program was not able to delete the sheet as it was already deleted

Sub Foo ()

    Application.DisplayAlerts = False

    On Error GoTo instructions
    Sheets("NAME OF THE SHEET").Delete

    instructions:

    Sheets.Add After:=Sheets(Sheets.Count)
    ActiveSheet.Name = "NAME OF THE SHEET"

End Sub
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • The problem with this answer is that upon determining that the sheet did in fact exist, it is deleted and therefore no longer exists. If this were written as a function it might have a name like SheetExistsAfterDeletion and would always return FALSE. – ChrisB Jul 26 '18 at 07:01