测试或检查工作表是否存在。

154
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

基本上,我通过循环遍历源工作簿中的所有工作表,然后将目标工作簿中的destsheet设置为与当前在原始工作簿中迭代的工作表同名的工作表。

如何测试该工作表是否存在?类似于:

If wkbkdestination.Worksheets(ThisWorkSheet.Name) Then 

2
可能是重复的问题:Excel VBA If WorkSheet("wsName") Exists - sancho.s ReinstateMonicaCellio
24个回答

244

有些人不喜欢这种方法,因为它使用了“不适当”的错误处理,但我认为在VBA中是可以接受的。另一种方法是循环所有工作表直到找到匹配项。

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

7
在我看来,这个使用完全合适。它是一个陷阱,用于假定存在但实际上不存在且有着悠久历史的事物 - 参见perl strict、STAE等。已顶。 - Wudang
22
在编写宏代码时,最好使用ActiveWorkbook而不是ThisWorkbook。后者指的是包含宏代码的工作簿,可能与想要测试的工作簿不同。我想ActiveWorkbook在大多数情况下会很有用(虽然总会有一些特殊情况)。 - sancho.s ReinstateMonicaCellio
4
如果没有与该名称对应的工作表,sht Is Nothing 将返回True,但我们希望在存在该名称的工作表时返回True,因此使用了 Not 操作符。如果稍微调整一下顺序, 可以更容易些(但不是有效的),即 SheetExists = sht Is Not Nothing - Tim Williams
4
请注意,如果您在个人宏工作簿中运行此代码,请将If wb Is Nothing Then Set wb = ThisWorkbook更改为If wb Is Nothing Then Set wb = ActiveWorkbook。该修改旨在确保代码正确引用活动工作簿而不是默认的工作簿。 - Henrik K
2
这是一种高效的方法(请参见我在Rory的回答下面关于基准测试的评论),所以谁在乎反对者的想法。注意(截至目前)你没有任何负面评价。 - rory.ap
显示剩余9条评论

128

如果您只对工作表感兴趣,可以使用简单的Evaluate调用:

Function WorksheetExists(sName As String) As Boolean
    WorksheetExists = Evaluate("ISREF('" & sName & "'!A1)")
End Function

18
我进行了与Tim Williams回答的基准测试比较。在超过500,000个循环的情况下,你的用时为22秒,而Tim的用时小于1秒。 - rory.ap
29
@roryap - 如果你需要运行这个程序500,000次,你需要重新考虑你的整体方法 ;) - Rory
11
@roryap - 但是,使用多个缓慢的方法会逐渐积累时间。我认为这是非常有价值的信息,因为在使用各种区域方法等Excel“应用程序”时,秒数很容易堆积起来。 - tedcurrent
5
@roryap - 这些信息在对话中有什么价值?我只是在陈述,将低效的方法分散在代码中会使整个应用程序变慢。你测试这个500k次是很棒的,我感谢你的付出,但22秒并不太好。(我同意你的观点) - tedcurrent
8
即使速度较慢,它看起来比被接受的答案更为简洁。我给你点个赞。 - Sascha L.
显示剩余6条评论

72

要完成这个任务,您不需要进行错误处理。您只需对所有工作表进行迭代,并检查指定名称是否存在:

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

2
小心,工作表名称不区分大小写: https://www.howtoexcel.org/how-to-check-if-a-worksheet-exists-using-vba/ - LePatay

30

我写了这个:

Function sheetExist(sSheet As String) As Boolean
On Error Resume Next
sheetExist = (ActiveWorkbook.Sheets(sSheet).Index > 0)
End Function

1
很棒的函数!它不仅快速,而且也是最简洁的。 - ChrisB
我相信这是最符合问题的答案。 - Juan Joya
2
我喜欢这个。请注意,它依赖于sheetExist的默认值为False,因为它是一个布尔函数。如果该工作表不存在,则赋值语句实际上不会将False值分配给sheetExist,而只是出错并保留默认值。如果您愿意,可以依赖于将任何非零值分配给布尔变量将产生True结果,并省略> 0比较,如下所示:sheetExist = ActiveWorkbook.Sheets(sSheet).Index - oddacorn

23

由于检查集合成员是一个通用的问题,因此这里提供了@Tim答案的抽象版本:

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

这个函数可以与任何集合对象一起使用(Shapes, Range, Names, Workbooks等)。

要检查工作簿中是否存在一个工作表,请使用If Contains(Sheets, "SheetName") ...


5
在集合中使用原始类型时,Set关键字会引发错误,因此它无法捕捉到。我发现,与其使用Set,请求集合成员的TypeName对于所有情况都有效,即TypeName objCollection(strName) - citizenkong
2
@Peter:最好添加一些内容来清除在函数终止之前可能引发的不存在错误-可以是err.clear或On Error Resume Next。否则,在调用过程中的错误处理可能会在以下情况下意外触发。“Sub Test() On Error GoTo errhandler Debug.Print Contains(Workbooks, "SomeBookThatIsNotOpen") errhandler: If Err.Number <> 0 Then StopEnd Sub” - jeffreyweir
嗨,我无法让形状起作用,是我漏掉了什么吗? - undefined

18

更正: 没有错误处理:

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

15

如果有人想避免使用VBA并且仅使用单元格公式测试工作表是否存在,则可以使用ISREFINDIRECT函数:

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

如果工作簿中包含名为SheetName的工作表,则此公式将返回TRUE,否则返回FALSE


8

紧凑的wsExists函数无需依赖错误处理!

这是一个简短且简单的函数,不依赖错误处理来确定工作表是否存在(并且任何情况下都可以正常工作!)

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

示例用法:

以下示例将添加一个名为myNewSheet的新工作表(如果不存在):

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

更多信息:


5
我的解决方案与Tim的类似,但也适用于非工作表工作表——图表。
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

.


4

简洁明了:

Function IsSheet(n$) As Boolean
    IsSheet = Not IsError(Evaluate("'" & n & "'!a1"))
End Function

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接