Sprawdź lub sprawdź, czy arkusz istnieje

115
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

Zasadniczo przeglądam wszystkie arkusze w skoroszycie źródłowym, a następnie ustawiam destsheetw skoroszycie docelowym arkusz o tej samej nazwie, co obecnie iterowany arkusz w skoroszycie źródłowym.

Jak mogę sprawdzić, czy ten arkusz istnieje? Coś jak:

If wkbkdestination.Worksheets(ThisWorkSheet.Name) Then 
yse
źródło
2
możliwy duplikat Excel VBA, jeśli istnieje arkusz roboczy („wsName”)
sancho.s ReinstateMonicaCellio,

Odpowiedzi:

173

Niektórzy ludzie nie lubią tego podejścia z powodu „niewłaściwego” użycia obsługi błędów, ale myślę, że jest to akceptowalne w VBA ... Alternatywnym podejściem jest zapętlenie wszystkich arkuszy, aż znajdziesz dopasowanie.

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
Tim Williams
źródło
5
Całkowicie odpowiednie użycie IMO. To pułapka na rzecz, która jest uznawana za istniejącą i nie ma jej i ma długą historię - por. Perl strict, STAE itp. Uznano za
Wudang
13
Prawdopodobnie należy użyć ActiveWorkbookzamiast ThisWorkbook. To ostatnie odnosi się do skoroszytu zawierającego kod makra, który może różnić się od skoroszytu, niż chce się przetestować. Myślę, że ActiveWorkbookprzydałby się w większości przypadków (jednak wymyślone sytuacje są zawsze dostępne).
sancho.s ReinstateMonicaCellio,
3
sht Is Nothingbędzie True, jeśli nie ma arkusz o tej nazwie, ale chcemy wrócić True, jeśli nie jest arkusz o tej nazwie, stąd też nie. Jest to trochę łatwiejsze (ale nie ważne), jeśli trochę zmienisz ustawienieSheetExists = sht Is Not Nothing
Tim Williams
3
Warto zauważyć, że jeśli uruchomisz ten kod w swoim osobistym skoroszycie makr, zmień z If wb Is Nothing Then Set wb = ThisWorkbooknaIf wb Is Nothing Then Set wb = ActiveWorkbook
Henrik K,
2
To bardzo efektywne podejście (zobacz moje komentarze na temat benchmarków poniżej odpowiedzi Rory'ego), więc kogo obchodzi, co myślą krytycy. Uwaga (na razie) masz zero głosów negatywnych.
rory.ap
107

Jeśli jesteś szczególnie zainteresowany tylko arkuszami roboczymi, możesz skorzystać z prostego wezwania do oceny:

Function WorksheetExists(sName As String) As Boolean
    WorksheetExists = Evaluate("ISREF('" & sName & "'!A1)")
End Function
Rory
źródło
14
@Rory Przeprowadziłem kilka testów porównawczych w porównaniu z odpowiedzią Tima Williamsa. Ponad 500 000 pętli, twoja zajęła 22 sekundy, a Timowi <1.
rory.ap
17
@roryap - jeśli chcesz uruchomić te 500 000 razy, musisz przemyśleć całe swoje podejście. ;)
Rory
9
@roryap - jednak użycie kilku powolnych metod zacznie piętrzyć się kilka sekund. Powiedziałbym, że są to niezwykle cenne informacje, ponieważ „aplikacje” Excela dość łatwo
zaczynają zbierać
4
@roryap - w jaki sposób te informacje są cenne w rozmowie? Po prostu stwierdzam, że rozproszenie nieefektywnych metod wokół twojego kodu spowolni działanie aplikacji jako całości. testowanie tego 500k razy jest niesamowite i dziękuję za zrobienie tego, 22 sekundy nie są świetne. (Zgadzam się z tobą)
tedcurrent
6
Nawet jeśli jest wolniejsze, wygląda na znacznie czystsze rozwiązanie niż zaakceptowana odpowiedź. +1 ode mnie.
Sascha L.,
49

Aby to osiągnąć, nie potrzebujesz obsługi błędów. Wszystko, co musisz zrobić, to powtórzyć wszystkie arkusze robocze i sprawdzić, czy określona nazwa istnieje:

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
fbonetti
źródło
21

Ponieważ sprawdzanie członków kolekcji jest ogólnym problemem, oto abstrakcyjna wersja odpowiedzi Tima:

Funkcja zawiera (objCollection As Object, strName as String) As Boolean
    Dim o jako Object
    Przy błędzie Wznów Dalej
    set o = objCollection (strName)
    Zawiera = (Err.Number = 0)
    Wyczyść
 Funkcja zakończenia

Funkcja ta może być stosowana do każdego zbioru, jak obiekt ( Shapes, Range, Names, Workbooks, itd.).

Aby sprawdzić istnienie arkusza, użyj If Contains(Sheets, "SheetName") ...

Peter Albert
źródło
5
Nie obejmuje to typów pierwotnych w kolekcjach, ponieważ Setsłowo kluczowe zgłosi błąd . Okazało się, że zamiast używać Set, proszenie TypeNameczłonka kolekcji działa we wszystkich przypadkach, tj.TypeName objCollection(strName)
citizenkong
2
@Peter: Najlepiej dodać coś, co usunie błąd, który zostanie zgłoszony w przypadku braku istnienia przed zakończeniem funkcji - albo err.clear, albo On Error Resume Next. W przeciwnym razie obsługa błędów w procedurze wywołującej może zostać przypadkowo wyzwolona w przypadkach takich jak poniżej. Sub Test() On Error GoTo errhandler Debug.Print Contains(Workbooks, "SomeBookThatIsNotOpen") errhandler: If Err.Number <> 0 Then Stop End Sub
jeffreyweir
16

Poprawione: bez obsługi błędów:

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
źródło
14

W przypadku, gdy ktoś chce uniknąć VBA i sprawdzić, czy arkusz istnieje wyłącznie w formule komórki, można użyć funkcji ISREFi INDIRECT:

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

Zwróci to, TRUEjeśli skoroszyt zawiera arkusz o nazwie SheetNamelub w FALSEinny sposób.

VirtualMichael
źródło
12

Napisałem to:

Function sheetExist(sSheet As String) As Boolean
On Error Resume Next
sheetExist = (ActiveWorkbook.Sheets(sSheet).Index > 0)
End Function
AOBR
źródło
1
Świetna funkcja! Jest nie tylko szybki, ale także najbardziej zwięzły.
ChrisB,
Wierzę, że to jest odpowiedź, która najbardziej odpowiada pytaniu
Juan Joya,
Podoba mi się ten. Zauważ, że opiera się na fakcie, że domyślną wartością dla sheetExist będzie False, ponieważ jest to funkcja logiczna. Instrukcja przypisania w rzeczywistości nie przypisuje wartości Fałsz do SheetExist, jeśli arkusz nie istnieje, po prostu wyświetla błąd i pozostawia wartość domyślną na miejscu. Jeśli chcesz, możesz polegać na fakcie, że każda niezerowa wartość przypisana do zmiennej boolowskiej da wynik True i sheetExist = ActiveWorkbook.Sheets(sSheet).Index
pominie
5

Moje rozwiązanie wygląda podobnie jak Tims, ale działa również w przypadku arkuszy innych niż arkusze - wykresów

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
źródło
3

Umieść test w funkcji, a będziesz mógł go ponownie użyć i będziesz mieć lepszą czytelność kodu.

NIE używaj opcji „Przy następnym wznowieniu błędu”, ponieważ może to powodować konflikt z inną częścią kodu.

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
źródło
3

Wiele lat spóźniłem się, ale po prostu musiałem to zrobić i nie podobało mi się żadne z opublikowanych rozwiązań ... Więc wymyśliłem jedno, wszystko dzięki magii (gest tęczowych rąk SpongeBoba) „Oceń ()”!

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

Zwraca wartość TRUE, jeśli arkusz NIE istnieje; FAŁSZ, jeśli arkusz istnieje. Możesz zamienić dowolny zakres na „1: 1”, ale odradzam używanie pojedynczej komórki, ponieważ jeśli zawiera błąd (np. # N / A), zwróci True.

X37V
źródło
3

Kompaktowa wsExistsfunkcja ( bez polegania na obsłudze błędów!)

Oto krótka i prosta funkcja, która nie polega na obsłudze błędów w celu określenia, czy arkusz istnieje ( i czy jest prawidłowo zadeklarowany do działania w każdej sytuacji!)

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

Przykładowe zastosowanie:

Poniższy przykład dodaje nowy arkusz o nazwie myNewSheet, jeśli jeszcze nie istnieje:

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

Więcej informacji:

ashleedawg
źródło
2

Dlaczego po prostu nie użyć małej pętli do określenia, czy nazwany arkusz istnieje? Powiedz, czy szukasz arkusza roboczego o nazwie „Arkusz1” w aktualnie otwartym skoroszycie.

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
źródło
2

Jeśli jesteś fanem WorksheetFunction.lub pracujesz z kraju nieanglojęzycznego z programem Excel w języku innym niż angielski, jest to dobre rozwiązanie, które działa:

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

Lub w funkcji takiej jak ta:

Function WorksheetExists(sName As String) As Boolean
    WorksheetExists = Not WorksheetFunction.IsErr(Evaluate("'" & sName & "'!A1"))
End Function
Vityata
źródło
1
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
Philipp88
źródło
1
    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
źródło
1

Zmień „Dane” na dowolną nazwę arkusza, dla którego testujesz ...

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
gth826a
źródło
1

Bez wątpienia powyższa funkcja może działać, właśnie skończyłem z następującym kodem, który działa całkiem nieźle:

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

Uwaga: w tym Sheets_Namemiejscu proszę użytkownika o wprowadzenie nazwy, więc może to nie być to samo dla Ciebie.

MAx Segura
źródło
0

Zrobiłem inną rzecz: usuń arkusz tylko wtedy, gdy istnieje - aby nie otrzymać błędu, jeśli nie:

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
źródło
0

Wymyśliłem łatwy sposób na zrobienie tego, ale nie stworzyłem dla niego nowego subwoofera. Zamiast tego po prostu „sprawdziłem” w subie, nad którym pracowałem. Zakładając, że nazwa arkusza, którego szukamy, to „Sheet_Exist” i chcemy ją po prostu aktywować, jeśli zostanie znaleziona:

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

Dodałem również wyskakujące okienko, gdy arkusz nie istnieje.

imjordy23
źródło
0

Wiem, że to stary post, ale oto inne proste rozwiązanie, które jest szybkie.

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
Gość
źródło
0

Krótkie i czyste:

Function IsSheet(n$) As Boolean
    IsSheet = Not IsError(Evaluate(n & "!a1"))
End Function
Excel Hero
źródło
-4

Właściwie miałem prosty sposób, aby sprawdzić, czy arkusz istnieje, a następnie wykonać jakąś instrukcję:

W moim przypadku chciałem usunąć arkusz, a następnie odtworzyć ten sam arkusz o tej samej nazwie, ale kod został przerwany, jeśli program nie mógł usunąć arkusza, ponieważ został już usunięty

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
chenaou
źródło
Problem z tą odpowiedzią polega na tym, że po ustaleniu, że arkusz faktycznie istniał, jest on usuwany, a zatem już nie istnieje. Gdyby to zostało zapisane jako funkcja, mogłoby mieć nazwę taką jak SheetExistsAfterDeletion i zawsze zwracałoby FALSE.
ChrisB