Excel VBA Userform: Suche nach Intervall von Geburtsjahren in einer Tabelle

  • Excel

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von tamtoff.

    Excel VBA Userform: Suche nach Intervall von Geburtsjahren in einer Tabelle

    Hallo liebe Forums-Mitglieder,


    ich habe mich frisch hier angemeldet und schon ein paar Zeilen in den Vorstellungs-Thread geschrieben. Nun gehts an die Arbeit, ich brauche eure Hilfe.

    [Hintergrund]
    Ich soll für meinen Arbeitgeber eine Filter- und Suchfunktion mit Hilfe einer Excel-Userform (in Excel 2007 unter Win7) programmieren. Es existiert ein Excel-Tabellenblatt mit ca. 1600 Personen, denen jeweils diverse Daten zugeordnet sind (Name, Geburtsdatum, Teilnahme an verschiedenen Seminaren etc.). Insgesamt sind es rund 60 Daten-Items pro Person. Da die Filterung über die hauseigene Excel-Filterfunktion recht aufwendig ist, muss ich nun eine Userform programmieren, die alle benötigten Filter kompakt darstellt und ausführt. Die Suchergebnisse werden dann in ein zweites Tabellenblatt kopiert. Momentan klappt das alles schon sehr gut, aber im nachfolgend beschriebenen Fall komme ich nicht weiter.

    [Problem/Frage]
    Ich möchte in der Userform mit Hilfe zweier Textboxen ein Intervall festlegen, innerhalb dessen das Geburtsjahr der gesuchten Personen liegen muss (in die erste Textbox kommt z.B. "1960" und in die zweite Textbox kommt "1980", ich will dann eine Suche nach Personen mit Geburtsjahr 1960-1980 starten). Mein bisheriger Gedanke: Eine Schleife, die das Intervall durchläuft und im Tabellenblatt bei jeder Person eine Übereinstimmung des Geburtsjahres mit dem Intervall sucht. Wenn eine Übereinstimmung gefunden wurde, soll True zurückgegeben werden und dann gehts weiter zur nächsten Person.

    Mein bisheriger Code (siehe unten) produziert keine Fehlermeldung, aber er findet nie etwas, obwohl passende Daten vorhanden sind.


    Erläuterung:

    "TB_vonJahr" ist die Textbox mit dem Anfang des Suchintervalls, "TB_bisJahr" analog dazu das Ende des Intervalls.

    Wenn die Funktion fGeburtsjahr als True an die eigentliche Suchmaschinenfunktion zurückgegeben wird, kopiert die Suchmaschinenfunktion die Daten des Probanden in ein neues Tabellenblatt. Die Suchmaschinenfunktion läuft mit diversen anderen Filtern wie am Schnürchen, daran sollte es nicht liegen. Wo (in welcher Spalte) nach den Daten gesucht werden soll, ist in der Suchmaschinenfuntkion hinterlegt, das muss also nicht in die hier beschriebene Funktion.

    VB.NET-Quellcode

    1. Function fGeburtsjahr(Cell As Range) As Boolean
    2. Dim i As Long 'Variable für Anfang des Intervalls
    3. Dim j As Long 'Variable für Ende des Intervalls
    4. Dim c As Long 'Zählvariable
    5. Dim TestComp1 As Integer
    6. TestComp1 = StrComp(Cell, c, vbTextCompare)
    7. Me.TB_vonJahr = i
    8. Me.TB_bisJahr = j
    9. For c = i To j
    10. If TestComp1 = 0 Then
    11. fGeburtsjahr = True
    12. End If
    13. c = c + 1
    14. Next c
    15. If Cell = c And TestComp1 = 0 Then
    16. fGeburtsjahr = True
    17. End If
    18. End Function



    Ich hoffe, bis hierhin sind sowohl Problem als auch gewünschter Zielzustand verständlich geworden und der ein oder andere hat einen Tipp parat. Alles, was ich bisher mit VBA programmiert habe, ist learning by doing; versucht euch deshalb bitte so einfach wie möglich auszudrücken :)


    Vielen Dank!


    Alex
    Du möchtest eine Funktion, die dir signalisiert, ob ein Datum in einem bestimmten Jahresintervall liegt?

    Visual Basic-Quellcode

    1. Function isInInterval(ByVal RefDate As Date, ByVal StartYear as Integer, ByVal EndYear As Integer) As Boolean
    2. isInInterval = Year(RefDate) >= StartYear And Year(RefDate) <= EndYear
    3. End Function
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Hallo petaod,


    ein simpler "kleiner gleich"/"größer gleich" - Vergleich. Hätte ich selbst drauf kommen können :D Manchmal denkt man doch etwas zu kompliziert... Danke für deine Hilfe. Noch kann ich nicht sagen, obs funktioniert, da ich erst morgen wieder an der Userform arbeite, aber ich denke das kriege ich hin. Ich melde mich auf jeden Fall nochmal :)
    Ich habe heute den Code von petaod und einige eigene Abwandlungen davon ausprobiert und leider hat es nicht geklappt. Entweder ich bekomme keine Fehlermeldung, aber auch keine Suchergebnisse (also wie im Anfangspost beschrieben), oder aber bei manchen Abwandlungen kommt eine Fehlermeldung, dass der Speicher nicht ausreichend sei oder "das Argument nicht optional" sei. Muss wohl nochmal tüfteln...
    Ja, hier sind meine Versuche:

    VB.NET-Quellcode

    1. Function Suchmaschine (fzeile as Integer, fzeilenanzahl as Integer, fRprob as Integer)
    2. 'Suchmaschinenfunktion, hier natürlich auf den Aufruf von fGeburtsjahr verkürzt und nur zum allg. Verständnis
    3. With Sheets("Daten")
    4. For fzeile = 3 To fzeilenanzahl 'fzeilenanzahl ist die Gesamtanzahl der Zeilen im Blatt, wird woanders ermittelt
    5. If fGeburtsjahr(Cells(fzeile, 10)) = True Then
    6. Rows(fzeile).Copy Worksheets("Suchergebnisse").Rows(fRprob)
    7. fRprob = fRprob + 1
    8. End If
    9. Next fzeile
    10. End With
    11. End Function
    12. '====================================================
    13. Function fGeburtsjahr (Cell As Range) As Boolean 'Version 1
    14. 'führt zur Fehlermeldung "Nicht genügend Speicher"
    15. If Me.TB_vonJahr >= Cells() And Me.TB_bisJahr <= Cells() Then
    16. fGeburtsjahr = True
    17. End If
    18. End Function
    19. '====================================================
    20. Function fGeburtsjahr (Cell As Range) As Boolean 'Version 2 (Unterschied zu V1 nur in If-Bedingung)
    21. 'liefert keine Ergebnisse (obwohl passende Einträge vorhanden wären)
    22. 'und liefert auch keine Fehlermeldung
    23. If Me.TB_vonJahr >= Cell And Me.TB_bisJahr <= Cell Then
    24. fGeburtsjahr = True
    25. End If
    26. End Function


    Ich vermute, dass mein Problem haptsächlich ist, dass ich nicht weiß, wie ich die Zelle im Datenblatt richtig anspreche, bzw. wie ich dem Code sage, dass er mit dem Inhalt "dieser" bestimmten Zelle vergleichen soll. An sich ist die Spaltenzahl und die durchlaufende Zeilenzahl ja in der Suchmaschinenfunktion drin, aber es klappt halt trotzdem nicht (zugegebenermaßen habe ich eher rumprobiert, denn im Internet habe ich keine passende Lösung gefunden).

    Am besten wäre es, wenn die Funktion einfach nur Integer miteinander vergleicht, denn ich brauche noch mehrere Intervall-Vergleiche in meiner Userform und eine Spezialisierung auf Jahreszahlen würde mir eine schnelle Anpassung des Codes erschweren :)


    Danke bis hierhin,

    Alex

    tamtoff schrieb:

    Me.TB_vonJahr >= Cell And Me.TB_bisJahr <= Cell
    Vergleich ist falsch rum.

    tamtoff schrieb:

    Me.TB_vonJahr >= Cells()
    Ist Blödsinn.
    Du übergibst Cell und fragst Cells ab.
    Als Cells bekommst du hier das Objekt Worksheet.Cells. Das ist eine Array der Größe 1048576 x 16384
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    petaod schrieb:

    tamtoff schrieb:

    Me.TB_vonJahr >= Cell And Me.TB_bisJahr <= Cell
    Vergleich ist falsch rum.


    Stimmt, Mist. Ich habe es jetzt richtig formuliert, aber das Problem bleibt: Keine Fehlermeldung und keine Suchergebnisse, obwohl passende Daten vorhanden sind.

    VB.NET-Quellcode

    1. Function fGeburtsjahr (Cell As Range) As Boolean
    2. If Cell >= Me.TB_vonJahr And Cell <= Me.TB_bisJahr Then
    3. fGeburtsjahr = True
    4. End If
    5. End Function


    Langsam zweifle ich an meinem Verstand. Entweder ich stehe gerade richtig auf dem Schlauch und die Lösung ist unglaublich banal, oder Excel macht Mist. Keine Ahnung.
    Wahrscheinlich vergleichst du Birnen mit Äpfeln.
    Cell ist ein Range-Objekt.
    Das zu einem Vergleich heranzuziehen ist zwar frech, aber es geht, weil die Default-Property .Value verwendet wird.
    Sauber wäre allerdings Cell.Value zu vergleichen.

    TB_bisJahr riecht verdammt nach Textbox.
    Wenn nun also in Cell.Value eine Zahl drin steht und in der Textbox ein Text, dann ist das nicht dasselbe.
    Das müsstest du aber im Debugger sehen.

    Was steht in den Textboxen drin und was steht in der Zelle drin?

    Ausserdem Ist eine Abprüfung eines Booleschen Ausdrucks auf True ein Vergehen gegen den gesunden Menschenverstand.

    Visual Basic-Quellcode

    1. Function fGeburtsjahr (Cell As Range) As Boolean
    2. fGeburtsjahr = Val(Cell.Value) >= Val(Me.TB_vonJahr) And Val(Cell.Value) <= Val(Me.TB_bisJahr)
    3. End Function


    Auch noch eine Todsünde ist die Verwendung von globalen Variablen innerhalb der Funktion (deine Textboxen).
    Wenn du diese auch noch beseitigst und statt dessen die Parameter beim Aufruf mitgibst, sind wir plötzlich wieder nahezu bei meinem Vorschlag aus Post #2.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „petaod“ ()

    Danke für die Hinweise. Ich werde mich voraussichtlich nächste Woche wieder damit beschäftigen, vorher komme ich nicht dazu.

    Kurz vorweg: TB steht tatsächlich für Textbox; da kommen Jahreszahlen im Format jjjj rein. In den Zellen der Tabelle sind ebenfalls Jahreszahlen im Format jjjj drin, aber die Zellen sind als normale Zahlen ohne Kommastellen formatiert. Dementsprechend erachte ich einen normalen Integer-Vergleich als passend, da es der Userform ja egal sein sollte, ob es Jahreszahlen oder sonstwas sind. Zudem brauche ich auch woanders weitere Integer-Vergleiche und würde so hoffentlich mehrere Fliegen mit einer Klappe schlagen.

    tamtoff schrieb:

    da es der Userform ja egal sein sollte, ob es Jahreszahlen oder sonstwas sind
    Der Userform ist egal, was drin steht.
    In der Textbox steht Text. Und in der Zelle steht eine Zahl.
    Aber "2015" <> 2015!
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „petaod“ ()

    So, da bin ich wieder. Ich hatte bisher noch keine Zeit, mich weiter mit der Userform zu beschäftigen und vermutlich wird es in den nächsten Wochen so bleiben. Ich wurde auf Arbeit kurzfristig in ein anderes Projekt verfrachtet, wo gerade einiges zu erledigen ist, was höhere Priorität hat. Wenn ich wieder weiter programmieren kann, werde ich mir deine Hinweise anschauen und schauen, wie ich damit zurecht komme.

    Grüße,

    Alex