【问题标题】:Test or check if sheet exists测试或检查工作表是否存在
【发布时间】:2011-10-05 00:17:56
【问题描述】:
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 

【问题讨论】:

标签: excel vba scripting


【解决方案1】:

有些人不喜欢这种方法,因为“不恰当”地使用错误处理,但我认为它在 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

【讨论】:

  • 完全适合使用 IMO。对于假定存在但不存在且历史悠久的事物来说,这是一个陷阱 - cf perl strict、STAE 等。赞成
  • 应该使用ActiveWorkbook 而不是ThisWorkbook。后者指的是包含宏代码的工作簿,它可能与想要测试的工作簿不同。我猜ActiveWorkbook 在大多数情况下都很有用(不过,人为的情况总是可用的)。
  • sht Is Nothing 将是 True 如果没有具有该名称的工作表,但如果存在 is 具有该名称的工作表,我们希望返回 True,因此不是。如果您重新安排一点到SheetExists = sht Is Not Nothing,它会更容易一些(但无效)
  • 请注意,如果您在个人宏工作簿中运行此代码,请将 If wb Is Nothing Then Set wb = ThisWorkbook 更改为 If wb Is Nothing Then Set wb = ActiveWorkbook
  • 这是一种高效的方法(请参阅下面 Rory 回答下的基准测试我的 cmets),所以谁在乎批评者的想法。请注意(截至目前)您的反对票为零。
【解决方案2】:

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

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

【讨论】:

  • @Rory 我对此与蒂姆威廉姆斯的回答进行了一些基准测试。超过 500,000 次循环,你的用时 22 秒,而蒂姆的用时
  • @roryap - 如果您需要运行 500,000 次,您需要重新考虑您的整个方法。 ;)
  • @roryap - 但是,使用几种缓慢的方法会开始累积秒数。我会说这是非常有价值的信息,因为 Excel“应用程序”开始使用各种 Range 方法等很容易地运行几秒钟。
  • @roryap - 信息对对话有何价值?我只是说在代码周围分散低效的方法会使整个应用程序变慢。你测试这 500k 次太棒了,我感谢你这样做,22 秒不是很好。 (我同意你的观点)
  • 即使速度较慢,它看起来也比公认的答案更干净。来自我的 +1。
【解决方案3】:

您不需要错误处理来完成此操作。您所要做的就是遍历所有工作表并检查指定的名称是否存在:

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

【讨论】:

    【解决方案4】:

    由于检查集合的成员是一个普遍的问题,这里是@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
    

    此函数可用于任何集合,如对象(ShapesRangeNamesWorkbooks 等)。

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

    【讨论】:

    • 这不会捕获集合中的原始类型,因为Set 关键字会引发错误。我发现不是使用Set,而是要求集合成员的TypeName适用于所有情况,即TypeName objCollection(strName)
    • @Peter:最好添加一些东西来清除在函数终止之前不存在的情况下会引发的错误——要么是 err.clear 要么是 On Error Resume Next。否则,调用过程中的错误处理可能会在以下情况下被无意触发。 Sub Test() On Error GoTo errhandler Debug.Print Contains(Workbooks, "SomeBookThatIsNotOpen") errhandler: If Err.Number <> 0 Then Stop End Sub
    【解决方案5】:

    更正: 没有错误处理:

    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
    

    【讨论】:

      【解决方案6】:

      这是我写的:

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

      【讨论】:

      • 很棒的功能!不仅速度快,而且最简洁。
      • 我相信这是最符合问题的答案
      • 我喜欢这个。请注意,它依赖于 sheetExist 的默认值为 False 的事实,因为它是一个布尔函数。如果工作表不存在,赋值语句实际上不会为 sheetExist 分配 False 值,它只是出错并保留默认值。如果你愿意,你可以依赖这样一个事实,即分配给布尔变量的任何非零值都会给出 True 结果并省略 > 0 比较,如下所示:sheetExist = ActiveWorkbook.Sheets(sSheet).Index
      【解决方案7】:

      如果有人想避免使用 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"
        

        更多信息:

        【讨论】:

          【解决方案9】:

          我的解决方案看起来很像 Tims,但也适用于非工作表 - 图表

          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

          .

          【讨论】:

            【解决方案10】:

            晚了很多年,但我只是需要这样做并且不喜欢发布的任何解决方案......所以我做了一个,这一切都归功于(海绵宝宝彩虹手势)“Evaluate()”的魔力!

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

            如果 Sheet 不存在,则返回 TRUE;如果工作表确实存在,则为 FALSE。 您可以将任何您喜欢的范围替换为“1:1”,但我建议不要使用单个单元格,因为如果它包含错误(例如,#N/A),它将返回 True。

            【讨论】:

            • 我在代码中看到 2 个错误:(1)如果工作表存在,则会出现错误 13,因为 1:1(2)如果工作表名称包含空格并且存在,则代码返回 False。为了避免#N/A 问题,我使用了 CELL 函数。这对我有用:Evaluate("IsError(Cell(""col"",'" + vSheetName + "'!A1))") 如果工作表不存在,则在此处退出子:If Evaluate("IsError(Cell(""col"",'" + vSheetName + "'!A1))") Then Exit Sub
            【解决方案11】:

            将测试放在一个函数中,您将能够重用它,并且您具有更好的代码可读性。

            不要使用“On Error Resume Next”,因为它可能与您代码的其他部分发生冲突。

            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
            

            【讨论】:

              【解决方案12】:

              短而干净:

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

              【讨论】:

                【解决方案13】:

                为什么不只使用一个小循环来确定命名的工作表是否存在?假设您正在当前打开的工作簿中查找名为“Sheet1”的工作表。

                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
                

                【讨论】:

                  【解决方案14】:
                      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
                  

                  【讨论】:

                    【解决方案15】:

                    如果您是WorksheetFunction. 的粉丝,或者您在非英语国家/地区工作且使用非英语 Excel,这是一个很好的解决方案,非常有效:

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

                    或者在这样的函数中:

                    Function WorksheetExists(sName As String) As Boolean
                        WorksheetExists = Not WorksheetFunction.IsErr(Evaluate("'" & sName & "'!A1"))
                    End Function
                    

                    【讨论】:

                      【解决方案16】:
                      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
                      

                      【讨论】:

                        【解决方案17】:

                        将“数据”更改为您要测试的任何工作表名称...

                        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
                        

                        【讨论】:

                          【解决方案18】:

                          毫无疑问,上面的函数可以工作,我刚刚得到了下面的代码,它工作得很好:

                          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
                          

                          注意:Sheets_Name 是我要求用户输入名称的地方,所以这对你来说可能不一样。

                          【讨论】:

                            【解决方案19】:

                            我做了另一件事:仅当工作表存在时才删除工作表 - 如果不存在则不会出错:

                            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
                            

                            【讨论】:

                              【解决方案20】:

                              如果需要,我使用此函数检查并返回新的工作表名称。 WSname 是所需的工作表名称,而 WBCur 是您要签入的工作簿。我使用它是因为不需要错误处理,并且可以在创建新工作表时调用它。

                              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
                              

                              【讨论】:

                                【解决方案21】:

                                我想出了一个简单的方法来做到这一点,但我没有为它创建一个新的子。相反,我只是在我正在研究的潜艇中“进行了检查”。假设我们要查找的工作表名称是“Sheet_Exist”,我们只想在找到时激活它:

                                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
                                

                                当工作表不存在时,我还添加了一个弹出窗口。

                                【讨论】:

                                  【解决方案22】:

                                  我知道这是一篇旧帖子,但这是另一个快速的简单解决方案。

                                  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
                                  

                                  【讨论】:

                                    【解决方案23】:

                                    我其实有一个简单的方法来检查工作表是否存在,然后执行一些指令:

                                    在我的情况下,我想删除工作表,然后重新创建具有相同名称的同一个工作表,但如果程序无法删除工作表,因为它已经被删除,代码就会中断

                                    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
                                    

                                    【讨论】:

                                    • 这个答案的问题是,在确定工作表确实存在时,它被删除,因此不再存在。如果这被写成一个函数,它可能有一个像 SheetExistsAfterDeletion 这样的名字,并且总是返回 FALSE。
                                    猜你喜欢
                                    • 2018-09-08
                                    • 1970-01-01
                                    • 2022-11-15
                                    • 1970-01-01
                                    • 1970-01-01
                                    相关资源
                                    最近更新 更多