• Privacywetgeving
    Het is bij Helpmij.nl niet toegestaan om persoonsgegevens in een voorbeeld te plaatsen. Alle voorbeelden die persoonsgegevens bevatten zullen zonder opgaaf van reden verwijderd worden. In de vraag zal specifiek vermeld moeten worden dat het om fictieve namen gaat.

Ipv Range.Find en Range.FindNext een Range.FindLast method? [VBA]

Status
Niet open voor verdere reacties.

Ginger

Terugkerende gebruiker
Lid geworden
29 dec 2006
Berichten
2.972
Helpers, Ik kon er op internet zo ff niets over vinden en vraag me dus af of in VBA de methode uberhaupt bestaat. Ik ben dus op zoek naar een "Range.FindLast" methode. Nu doorloop ik met Range.Find en Range.FindNext voor elk artikel een forse tabel van 30.000 records op zoek naar het laatste record van dat artikel. Het lijkt mij dus véél efficiënter om van onderaf te starten met zoeken ipv vanaf de eerste regel. Het Z-A sorteren is geen optie overigens.
Wie heeft deze methode wel 'ns voorbij zien komen?
 
Kun je hier iets mee?
Wellicht de bereiken aanpassen.

Code:
Sub Laatste_Item_zoeken()
    Dim oRange As Range, aCell As Range, bCell As Range
    Dim ws As Worksheet
    Dim ExitLoop As Boolean
    Dim SearchString As String, FoundAt As String
    On Error GoTo Err
    Set ws = Worksheets(1)
    Set oRange = ws.Columns(1)
    zoekterm = InputBox("Watte ?:")
    SearchString = zoekterm
    Set aCell = oRange.Find(What:=SearchString, LookIn:=xlValues, _
                LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
                MatchCase:=False, SearchFormat:=False)
    If Not aCell Is Nothing Then
        Set bCell = aCell
        Gevonden = aCell.Address
        Do While ExitLoop = False
            Set aCell = oRange.FindNext(After:=aCell)

            If Not aCell Is Nothing Then
                If aCell.Address = bCell.Address Then Exit Do
                Gevonden = aCell.Address
                'Gevonden = Gevonden & ", " & aCell.Address
            Else
                ExitLoop = True
            End If
        Loop
    Else
        MsgBox SearchString & " niets gevonden"
    End If
    MsgBox "De laatste zoekterm is te vinden op regel : " & Gevonden
    Exit Sub
Err:
    MsgBox Err.Description
End Sub
 
Cobbe, onwijs bedankt voor je reactie en het schrijven van deze procedure. Wat dát betreft zitten we op 1 lijn. Zoiets dergelijks heb ik ook in m'n procedure. Maar het doorlopen van die hele tabel is het probleem. Per actieperiode wordt deze tabel groter en gaat het zoeken dus langer duren (ik bouw een nieuwe tabel op aan de hand van de actie-artikelen van deze periode en zoek daar dan in de grote tabel op of we - én wanneer dan - dit artikel al eerder in de actie hebben gehad).
Ik ben nu trouwens ff wat aan het stoeien met de Range.FindPrevious methode. Voor een deel werkt dit wel, maar het nare is dat je altijd een start moet maken met de Range.Find. Ofwel, er wordt tóch éérst van regel 1 naar regel N gekeken om daarna terug te keren via FindPrevious.
Ik zou dus eigenlijk willen dat FindPrevious direct al onderaan de grote tabel start met zoeken.

Als het écht gewenst is, kan ik wel een klein voorbeeld aanmaken. Voor mij voegt het niet echt iets toe omdat ik echt alleen maar op zoek ben naar iets van een echte opdracht FindLast. Maar het kan dus wel.... ;)
 
Ja ik was eigenlijk wat snel door de vraagstelling gelopen, zal er mij nog eens in verdiepen.
 
Maar bij 175000 rijen en 40 kolommen doet ie er bij mij 0.7 seconden over, dat kan toch niet het probleem zijn.
Code:
Sub Laatste_Item_zoeken()
    Dim oRange As Range, aCell As Range, bCell As Range
    Dim ws As Worksheet
    Dim ExitLoop As Boolean
    Dim SearchString As String, FoundAt As String
    On Error GoTo Err
    Set ws = Worksheets(1)
    Set oRange = ws.Range("A1:A" & ws.Cells(Rows.Count, 1).End(xlUp).Row)
    zoekterm = InputBox("Watte ?:")
    SearchString = zoekterm
tijd = Time
    Set aCell = oRange.Find(What:=SearchString, LookIn:=xlValues, _
                LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
                MatchCase:=False, SearchFormat:=False)
    If Not aCell Is Nothing Then
        Set bCell = aCell
        Gevonden = aCell.Address
        Do While ExitLoop = False
            Set aCell = oRange.FindNext(After:=aCell)

            If Not aCell Is Nothing Then
                If aCell.Address = bCell.Address Then Exit Do
                Gevonden = aCell.Address
                'Gevonden = Gevonden & ", " & aCell.Address
            Else
                ExitLoop = True
            End If
        Loop
    Else
        MsgBox SearchString & " niets gevonden"
    End If
    MsgBox "De laatste zoekterm is te vinden op regel : " & Gevonden & " in :" & Format(Time - tijd, "hh:mm:ss")
    Exit Sub
Err:
    MsgBox Err.Description

End Sub
 
Code:
Uit de vraag kan ik niet helemaal opmaken of je nu een specifieke kolom doorzoekt op artikel (artikelcode, artikelomschrijving, oid) of de hele tabel. Uitgaande van een specifieke kolom gaat het snel door gebruik te maken van het autofilter.

En anders is het misschien een idee om je zoekbereik te verkleinen.;)

Code:
Sub VenA()
Application.ScreenUpdating = False
With Sheets(1).Cells(1).CurrentRegion
    .AutoFilter 1, InputBox("Welk artikel?")
    Application.Goto .Cells(1).End(xlDown), True
    .AutoFilter
End With
End Sub

In het voorbeeldje gaat het zelfs tot het max aantal rijen redelijk snel.

Edit
Gezien de code van Cobbe moet de hele tabel doorzocht worden en dan zal het met een filter wat boven mijn pet gaan:d
 

Bijlagen

Laatst bewerkt:
Cobbe, Da's inderdaad heel snel. Ik moet ook zeggen dat het altijd redelijk vlot ging TOT vandaag. Ik heb eigenlijk geen idee wat er precies aan de hand is. Misschien eigenlijk beter om dát uit te zoeken ipv een nieuwe procedure in te zetten. ;)

Overigens heb ik nu wel een methode gevonden om aan het einde van een tabel te beginnen met zoeken en dan zo terug te lopen.
Code:
        With q2
            Set c = .Find(What:=Arti, After:=Range("C20374"), SearchDirection:=2, LookIn:=xlValues)
            If Not c Is Nothing Then
                firstAddress = c.Address
                Do
                    MsgBox c.Value & " " & c.Address
                    Set c = .FindPrevious(c)
                Loop While Not c Is Nothing And c.Address <> firstAddress
            End If
        End With
Met het inzetten van deze 2 parameters: After:=Range("C20374"), SearchDirection:=2 in de Find methode geef ik aan dat ik 1 regel onder de tabel moet starten en daarna omhoog moet gaan zoeken. De FindPrevious laat 'm dan verder door naar boven lopen. Ik hoef nu véél minder te controleren. Bij het eerste gevonden artikel moet ik kijken of deze wel of niet bij de huidige actie hoort. Zo niet, dan lus verlaten en de gevonden periode aangeven. Zo wel, dan door zoeken of er nog 1 wordt gevonden. Wordt er nog 1 gevonden, dan die periode aangeven en lus verlaten. Zo niet, dan aangeven dat het product niet eerder in de actie is geweest.

In elk geval mijn dank dat je deelgenoot wilde zijn van mijn probleem.
 
@V&A, Ook jij dank voor je reactie en het meedenken.
Filteren op het artikel en vervolgens die doorlopen. Hmmm... Is ook een optie. Die ga ik wel onthouden om wellicht 'ns uit te werken.
 
Ik hanteer: 2*zoeken=filteren.
'Find' is bedoeld voor slechts 1 keer zoeken (zoals additem ook alleen maar bedoeld is om 1 item toe te voegen en je, zodra het om meer gaat .list moet gebruiken)

In aansluiting op VenA;

Code:
Sub M_snb()
   Columns(1).AutoFilter 1, "aa10"
   with Columns(1).SpecialCells(12).SpecialCells(2)
      Application.Goto .Areas(.Areas.Count)
   end with
End Sub

Maar doorgaand op 'Find'
Code:
Sub M_snb()
'   vind laatste
   Sheet1.Columns(1).Find("aa10", Cells(Rows.Count, 1), , , , 2).Select
   
'  vind op 1 na laatste
   With Sheet1.Columns(1)
       .FindPrevious(.Find("aa10", Cells(Rows.Count, 1), , , , 2)).Select
   End With
   
'  vind op 2 na laatste
   With Sheet1.Columns(1)
       .FindPrevious(.FindPrevious(.Find("aa10", Cells(Rows.Count, 1), , , , 2))).Select
   End With
End Sub

of

Code:
Sub M_snb()
'   vind laatste
   Application.goto Sheet1.Columns(1).Find("aa10", Cells(Rows.Count, 1), , , , 2)
   
'  vind op 1 na laatste
   With Sheet1.Columns(1)
       Application.goto .FindPrevious(.Find("aa10", Cells(Rows.Count, 1), , , , 2))
   End With
   
'  vind op 2 na laatste
   With Sheet1.Columns(1)
       Application.goto .FindPrevious(.FindPrevious(.Find("aa10", Cells(Rows.Count, 1), , , , 2)))
   End With
End Sub
 
Laatst bewerkt:
@snb, Ook jij dank voor je mooie oplossingen. Daar ga ik zeker nog mee aan de slag.
Ook jouw opvatting over Find of Filter deel ik nu dus ook wel (nadat V&A me dat deed inzien). Overigens wel even iets van historie mbt dit issue. Ik heb inmiddels een kleine "database" aangelegd met de actieartikelen van de afgelopen jaren. Als we een nieuwe actie gaan krijgen, moet ik weten welke artikelen er eventueel "doorlopen" van de huidige actie in de nieuwe. Dit zijn namelijk dan artikelen die niet meer geteld mogen worden in de winkel (de winkelvoorraad) omdat we die voorraad van de automatische instuwing aftrekken. Toen de database nog klein was, toonde ik elke regel die ik kon vinden bij het artikel dat in de actie zou komen. Dat bleek in het "nu" bij sommige artikelen bizar te worden (zijn heel erg vaak in de actie) en gaf me dus enorme rapportages. Toen bedacht ik me dat ik voldoende had aan alleen de voorgaande actie om te bepalen of het artikel door loopt of niet. Zo heb ik mijn Find & FindNext procedure omgebouwd om alleen de een na laatste te tonen.
Al met al heb ik nu voldoende stof om mee te gaan stoeien en zo weer voorbereid 2016 in kan.
 
Hier is nog een mogelijkheid (Gary's Student code)
Code:
Sub Garys_Student()
    Dim c As Range, where As Range, whatt As String
    whatt = InputBox("Welk artikel?")
    Set c = Range("A:A")
    Set where = c.Find(what:=whatt, after:=c(1), searchdirection:=xlPrevious)
    MsgBox where.Address(0, 0)
End Sub
Voor het nummer van de rij alleen:
MsgBox Mid(where.Address(0, 0), 2)
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan