Fout bij het vinden van de laatst gebruikte cel in Excel met VBA

Als ik de laatst gebruikte celwaarde wil vinden, gebruik ik:

Dim LastRow As Long
LastRow = Range("E4:E48").End(xlDown).Row
Debug.Print LastRow

Ik krijg de verkeerde uitvoer wanneer ik een enkel element in een cel plaats. Maar als ik meer dan één waarde in de cel plaats, is de uitvoer correct.
Wat is de reden hierachter?


Antwoord 1, autoriteit 100%

OPMERKING: ik ben van plan om dit een “one-stop-post” te maken waar je de Correctmanier kunt gebruiken om de laatste rij te vinden. Dit omvat ook de best practices die moeten worden gevolgd bij het vinden van de laatste rij. En daarom zal ik het blijven updaten wanneer ik een nieuw scenario/informatie tegenkom.


Onbetrouwbare manieren om de laatste rij te vinden

Enkele van de meest voorkomende manieren om de laatste rij te vinden, zijn zeer onbetrouwbaar en mogen daarom nooit worden gebruikt.

  1. UsedRange
  2. xlOmlaag
  3. AantalA

UsedRangemag NOOITworden gebruikt om de laatste cel met gegevens te vinden. Het is hoogst onbetrouwbaar. Probeer dit experiment.

Typ iets in cel A5. Als je nu de laatste rij berekent met een van de onderstaande methoden, krijg je 5. Kleur nu de cel A10rood. Als je nu een van de onderstaande codes gebruikt, krijg je nog steeds 5. Als je Usedrange.Rows.Countgebruikt, wat krijg je dan? Het wordt geen 5.

Hier is een scenario om te laten zien hoe UsedRangewerkt.

xlDownis even onbetrouwbaar.

Overweeg deze code

lastrow = Range("A1").End(xlDown).Row

Wat zou er gebeuren als er maar één cel (A1) was met gegevens? Je komt uiteindelijk bij de laatste rij van het werkblad! Het is alsof u cel A1selecteert en vervolgens op de End-toets drukt en vervolgens op de Pijl-omlaag-toets drukt. Dit geeft ook onbetrouwbare resultaten als er lege cellen in een bereik zijn.

CountAis ook onbetrouwbaar omdat het een onjuist resultaat geeft als er lege cellen tussen staan.

En daarom moet men het gebruik van UsedRange, xlDownen CountAvermijden om de laatste cel te vinden.


Vind laatste rij in een kolom

Gebruik dit om de laatste rij in Col E te vinden

With Sheets("Sheet1")
    LastRow = .Range("E" & .Rows.Count).End(xlUp).Row
End With

Als je merkt dat we een .hebben vóór Rows.Count. We hebben er vaak voor gekozen om dat te negeren. Zie DEZEvraag over de mogelijke fout die u kunt krijgen. Ik raad altijd aan om .te gebruiken vóór Rows.Counten Columns.Count. Die vraag is een klassiek scenario waarbij de code zal mislukken omdat de Rows.Count65536voor Excel 2003 en eerder en 1048576voor Excel 2007 en later. Op dezelfde manier retourneert Columns.Countrespectievelijk 256en 16384.

Het bovenstaande feit dat Excel 2007+ 1048576rijen heeft, benadrukt ook het feit dat we altijd de variabele die de rijwaarde zal bevatten moeten declareren als Longin plaats van Integeranders krijg je een Overflow-fout.

Houd er rekening mee dat deze aanpak alle verborgen rijen overslaat. Terugkijkend op mijn screenshot hierboven voor kolom A, als rij 8 verborgen was, zou deze benadering retourneer 5in plaats van 8.


Vind laatste rij in een blad

Gebruik deze om de Effectivelaatste rij in het blad te vinden. Let op het gebruik van Application.WorksheetFunction.CountA(.Cells). Dit is vereist, want als er geen cellen met gegevens in het werkblad staan, geeft .Findu Run Time Error 91: Object Variable or With block variable not set

With Sheets("Sheet1")
    If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
        lastrow = .Cells.Find(What:="*", _
                      After:=.Range("A1"), _
                      Lookat:=xlPart, _
                      LookIn:=xlFormulas, _
                      SearchOrder:=xlByRows, _
                      SearchDirection:=xlPrevious, _
                      MatchCase:=False).Row
    Else
        lastrow = 1
    End If
End With

Vind laatste rij in een tabel (ListObject)

Dezelfde principes zijn van toepassing, bijvoorbeeld om de laatste rij in de derde kolom van een tabel te krijgen:

Sub FindLastRowInExcelTableColAandB()
Dim lastRow As Long
Dim ws As Worksheet, tbl as ListObject
Set ws = Sheets("Sheet1")  'Modify as needed
'Assuming the name of the table is "Table1", modify as needed
Set tbl = ws.ListObjects("Table1")
With tbl.ListColumns(3).Range
    lastrow = .Find(What:="*", _
                After:=.Cells(1), _
                Lookat:=xlPart, _
                LookIn:=xlFormulas, _
                SearchOrder:=xlByRows, _
                SearchDirection:=xlPrevious, _
                MatchCase:=False).Row
End With
End Sub

Antwoord 2, autoriteit 11%

Opmerking: dit antwoord werd gemotiveerd door deze opmerking. Het doel van UsedRangeis anders dan in het bovenstaande antwoord wordt vermeld.

Voor de juiste manier om de laatst gebruikte cel te vinden, moet men eerst beslissen wat als gebruiktwordt beschouwd en vervolgens een geschikte methode selecteren. Ik kan ten minste drie betekenissen bedenken:

  1. Gebruikt = niet leeg, d.w.z. met gegevens.

  2. Used = “… in gebruik, dat wil zeggen de sectie die gegevens of opmaakbevat.”
    Volgens officiële documentatieis dit het criterium dat door Excel wordt gebruikt op het moment van opslaan. Zie ook deze officiële documentatie.
    Als men zich dit niet bewust is, kan het criterium onverwachte resultaten opleveren, maar het kan ook opzettelijk worden gebruikt (minder vaak, zeker), bijvoorbeeld om specifieke regio’s te markeren of af te drukken, die uiteindelijk geen gegevens hebben.
    En natuurlijk is het wenselijk als criterium voor het bereik dat moet worden gebruikt bij het opslaan van een werkmap, om te voorkomen dat een deel van het werk verloren gaat.

  3. Used = “… in gebruik, dat wil zeggen de sectie die gegevens of opmaakof voorwaardelijke opmaak bevat.
    Hetzelfde als 2., maar ook met cellen die het doel zijn voor elke regel voor voorwaardelijke opmaak.

Hoe u de laatst gebruikte cel kunt vinden, hangt af van wat uwilt (uw criterium).

Voor criterium 1 raad ik aan dit antwoordte lezen.
Merk op dat UsedRangeals onbetrouwbaar wordt beschouwd. Ik denk dat dat misleidend is (d.w.z. “oneerlijk” voor UsedRange), aangezien UsedRangegewoon niet bedoeld is om de laatste cel met gegevens te rapporteren. Het mag in dit geval dus niet worden gebruikt, zoals aangegeven in dat antwoord. Zie ook deze opmerking.

Voor criterium 2 is UsedRangede meest betrouwbare optie, in vergelijking met andere opties die ook voor dit gebruik zijn ontworpen. Het maakt het zelfs overbodig om een ​​werkmap op te slaan om ervoor te zorgen dat de laatste cel wordt bijgewerkt.
Ctrl+Endgaat naar een verkeerde cel voorafgaand aan het opslaan
(“De laatste cel wordt pas gereset als u het werkblad opslaat”, van
http://msdn.microsoft.com/en -us/library/aa139976%28v=office.10%29.aspx.
Het is een oude referentie, maar in dit opzicht geldig).

Voor criterium 3 ken ik geen ingebouwde methode.
Criterium 2 houdt geen rekening met voorwaardelijke opmaak. Men kan opgemaakte cellen hebben, gebaseerd op formules, die niet gedetecteerd worden door UsedRangeof Ctrl+End.
In de afbeelding is de laatste cel B3, omdat er expliciet opmaak op is toegepast. Cellen B6:D7 hebben een indeling die is afgeleid van een regel voor voorwaardelijke opmaak en dit wordt zelfs niet gedetecteerd door UsedRange.
Om hier rekening mee te houden zou wat VBA-programmering nodig zijn.


Wat betreft uw specifieke vraag:
Wat is de reden hierachter?

Je code gebruikt de eerste cel in je bereik E4:E48 als trampoline, voor springennaar beneden met End(xlDown).

De “foutieve” uitvoer wordt verkregen als er geen niet-legecellen in uw bereik zijn, behalve misschien de eerste. Dan spring je in het donker, d.w.z. naar beneden op het werkblad
(let op het verschil tussen blancoen lege string!).

Let op:

  1. Als uw bereik niet-aaneengesloten niet-lege cellen bevat, geeft dit ook een verkeerd resultaat.

  2. Als er maar één niet-lege cel is, maar het is niet de eerste, geeft je code je nog steeds het juiste resultaat.


Antwoord 3, autoriteit 6%

Ik heb deze one-stop-functie gemaakt voor het bepalen van de laatste rij, kolom en cel, of het nu gaat om gegevens, opgemaakte (gegroepeerde/commentaar/verborgen) cellen of voorwaardelijke opmaak.

Sub LastCellMsg()
    Dim strResult As String
    Dim lngDataRow As Long
    Dim lngDataCol As Long
    Dim strDataCell As String
    Dim strDataFormatRow As String
    Dim lngDataFormatCol As Long
    Dim strDataFormatCell As String
    Dim oFormatCond As FormatCondition
    Dim lngTempRow As Long
    Dim lngTempCol As Long
    Dim lngCFRow As Long
    Dim lngCFCol As Long
    Dim strCFCell As String
    Dim lngOverallRow As Long
    Dim lngOverallCol As Long
    Dim strOverallCell As String
    With ActiveSheet
        If .ListObjects.Count > 0 Then
            MsgBox "Cannot return reliable results, as there is at least one table in the worksheet."
            Exit Sub
        End If
        strResult = "Workbook name: " & .Parent.Name & vbCrLf
        strResult = strResult & "Sheet name: " & .Name & vbCrLf
        'DATA:
        'last data row
        If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
            lngDataRow = .Cells.Find(What:="*", _
             After:=.Range("A1"), _
             Lookat:=xlPart, _
             LookIn:=xlFormulas, _
             SearchOrder:=xlByRows, _
             SearchDirection:=xlPrevious, _
             MatchCase:=False).Row
        Else
            lngDataRow = 1
        End If
        'strResult = strResult & "Last data row: " & lngDataRow & vbCrLf
        'last data column
        If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
            lngDataCol = .Cells.Find(What:="*", _
             After:=.Range("A1"), _
             Lookat:=xlPart, _
             LookIn:=xlFormulas, _
             SearchOrder:=xlByColumns, _
             SearchDirection:=xlPrevious, _
             MatchCase:=False).Column
        Else
            lngDataCol = 1
        End If
        'strResult = strResult & "Last data column: " & lngDataCol & vbCrLf
        'last data cell
        strDataCell = Replace(Cells(lngDataRow, lngDataCol).Address, "$", vbNullString)
        strResult = strResult & "Last data cell: " & strDataCell & vbCrLf
        'FORMATS:
        'last data/formatted/grouped/commented/hidden row
        strDataFormatRow = StrReverse(Split(StrReverse(.UsedRange.Address), "$")(0))
        'strResult = strResult & "Last data/formatted row: " & strDataFormatRow & vbCrLf
        'last data/formatted/grouped/commented/hidden column
        lngDataFormatCol = Range(StrReverse(Split(StrReverse(.UsedRange.Address), "$")(1)) & "1").Column
        'strResult = strResult & "Last data/formatted column: " & lngDataFormatCol & vbCrLf
        'last data/formatted/grouped/commented/hidden cell
        strDataFormatCell = Replace(Cells(strDataFormatRow, lngDataFormatCol).Address, "$", vbNullString)
        strResult = strResult & "Last data/formatted cell: " & strDataFormatCell & vbCrLf
        'CONDITIONAL FORMATS:
        For Each oFormatCond In .Cells.FormatConditions
            'last conditionally-formatted row
            lngTempRow = CLng(StrReverse(Split(StrReverse(oFormatCond.AppliesTo.Address), "$")(0)))
            If lngTempRow > lngCFRow Then lngCFRow = lngTempRow
            'last conditionally-formatted column
            lngTempCol = Range(StrReverse(Split(StrReverse(oFormatCond.AppliesTo.Address), "$")(1)) & "1").Column
            If lngTempCol > lngCFCol Then lngCFCol = lngTempCol
        Next
        'no results are returned for Conditional Format if there is no such
        If lngCFRow <> 0 Then
            'strResult = strResult & "Last cond-formatted row: " & lngCFRow & vbCrLf
            'strResult = strResult & "Last cond-formatted column: " & lngCFCol & vbCrLf
            'last conditionally-formatted cell
            strCFCell = Replace(Cells(lngCFRow, lngCFCol).Address, "$", vbNullString)
            strResult = strResult & "Last cond-formatted cell: " & strCFCell & vbCrLf
        End If
        'OVERALL:
        lngOverallRow = Application.WorksheetFunction.Max(lngDataRow, strDataFormatRow, lngCFRow)
        'strResult = strResult & "Last overall row: " & lngOverallRow & vbCrLf
        lngOverallCol = Application.WorksheetFunction.Max(lngDataCol, lngDataFormatCol, lngCFCol)
        'strResult = strResult & "Last overall column: " & lngOverallCol & vbCrLf
        strOverallCell = Replace(.Cells(lngOverallRow, lngOverallCol).Address, "$", vbNullString)
        strResult = strResult & "Last overall cell: " & strOverallCell & vbCrLf
        MsgBox strResult
        Debug.Print strResult
    End With
End Sub

De resultaten zien er als volgt uit:

Voor meer gedetailleerde resultaten kunnen sommige regels in de code worden verwijderd:

Er is één beperking: als er tabellen in het blad staan, kunnen de resultaten onbetrouwbaar worden, dus heb ik besloten de code in dit geval niet uit te voeren:

If .ListObjects.Count > 0 Then
    MsgBox "Cannot return reliable results, as there is at least one table in the worksheet."
    Exit Sub
End If

Antwoord 4, autoriteit 4%

Een belangrijke opmerking om in gedachten te houden bij het gebruik van de oplossing …

LastRow = ws.Cells.Find(What:="*", After:=ws.range("a1"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row

… is om ervoor te zorgen dat uw LastRow-variabele van het type Longis:

Dim LastRow as Long

Anders krijg je in bepaalde situaties OVERFLOW-fouten in .XLSX-werkmappen

Dit is mijn ingekapselde functie die ik gebruik voor verschillende codetoepassingen.

Private Function FindLastRow(ws As Worksheet) As Long
    ' --------------------------------------------------------------------------------
    ' Find the last used Row on a Worksheet
    ' --------------------------------------------------------------------------------
    If WorksheetFunction.CountA(ws.Cells) > 0 Then
        ' Search for any entry, by searching backwards by Rows.
        FindLastRow = ws.Cells.Find(What:="*", After:=ws.range("a1"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
    End If
End Function

Antwoord 5, autoriteit 4%

Aangezien de oorspronkelijke vraag gaat over problemenmet het vinden van de laatste cel, in dit antwoord zal ik de verschillende manieren opsommen waarop u onverwachte resultaten kunt krijgen; zie mijn antwoord op “Hoe vind ik de laatste rij die gegevens bevat in het Excel-blad met een macro?”voor mijn mening over het oplossen hiervan.

Ik zal beginnen met het antwoord door sancho.sen de opmerking van GlennFromIowa, nog meer details toevoegend:

[…] men moet eerst beslissen wat als gebruikt wordt beschouwd. Ik zie minstens 6 betekenissen. Cel heeft:

  • 1) gegevens, d.w.z. een formule, mogelijk resulterend in een lege waarde;
  • 2) een waarde, d.w.z. een niet-lege formule of constante;
  • 3) opmaak;
  • 4) voorwaardelijke opmaak;
  • 5) een vorm (inclusief commentaar) die de cel overlapt;
  • 6) betrokkenheid bij een tabel (lijstobject).

Op welke combinatie wilt u testen? Sommige (zoals tabellen) kunnen moeilijker te testen zijn en sommige zijn zeldzaam (zoals een vorm buiten het gegevensbereik), maar andere kunnen variëren op basis van de situatie (bijv. formules met lege waarden).

Andere dingen die u zou kunnen overwegen:

  • A) Kunnen er verborgen rijen(bijv. autofilter), lege cellenof lege rijen zijn?
  • B) Wat voor soort prestatie is acceptabel?
  • C) Kan de VBA-macro de werkmap of de applicatie-instellingen op enigerlei wijze beïnvloeden?

Laten we met dat in gedachten eens kijken hoe de gebruikelijke manieren om de “laatste cel” te krijgen onverwachte resultaten kunnen opleveren:

  • De .End(xlDown)-code van de vraag zal het gemakkelijkst breken (bijv. met een enkele niet-lege celof wanneer er lege cellen in tussen) om de redenen uitgelegd in de antwoord door Siddharth Routhier (zoek naar “xlDown is even onbetrouwbaar.”) 👎
  • Elke oplossing op basis van Counting (CountAof Cells*.Count) of .CurrentRegionzal ook breken in aanwezigheid van lege cellen of rijen 👎
  • Een oplossing met .End(xlUp)om achteruit te zoeken vanaf het einde van een kolom zal, net als CTRL+UP, zoeken naar gegevens(formules die een spatie produceren waarde worden beschouwd als “gegevens”) in zichtbare rijen(dus het gebruik ervan met autofilter ingeschakeld kan onjuiste resultaten opleveren ⚠️).

    Je moet ervoor zorgen dat je de standaard valkuilen vermijdt (voor details verwijs ik opnieuw naar het antwoord van Siddharth Routhier, zoek de sectie “Vind laatste rij in een kolom”), zoals hard-coding van de laatste rij (Range("A65536").End(xlUp)) in plaats van te vertrouwen op sht.Rows.Count.

  • .SpecialCells(xlLastCell)is gelijk aan CTRL+END en retourneert de onderste en meest rechtse cel van het “gebruikte bereik”, dus alle voorbehouden die van toepassing zijn op het vertrouwen op het “gebruikte bereik”. bereik”, zijn ook van toepassing op deze methode. Bovendien wordt het “gebruikte bereik” alleen gereset bij het opslaan van de werkmap en bij het openen van worksheet.UsedRange, dus xlLastCellkan verouderde resultaten opleveren⚠️ met niet-opgeslagen wijzigingen (bijv. rijen zijn verwijderd). Zie het antwoord in de buurt van dotNET.
  • sht.UsedRange(in detail beschreven in het antwoord van sancho.shier) houdt rekening met zowel gegevens als opmaak(hoewel niet voorwaardelijke opmaak) en stelt het “gebruikte bereik” van het werkblad opnieuw in, wat al dan niet is wat je wilt.

    Merk op dat een veelvoorkomende fout ️is om .UsedRange.Rows.Count⚠️ te gebruiken, wat het aantal rijenin het gebruikte bereik, niet het laatste rijnummer(ze zullen anders zijn als de eerste paar rijen leeg zijn), zie voor details newguy’s antwoord op Hoe kan ik de laatste rij met gegevens in het Excel-blad vinden met een macro?

  • .Findstelt u in staat om de laatste rij met alle gegevens (inclusief formules) of een niet-lege waarde in elke kolomte vinden. U kunt kiezen of u geïnteresseerd bent in formules of waarden, maar het addertje onder het gras is dat het de standaardinstellingen in het Excel-dialoogvenster Zoeken terugzet️️⚠️, wat zeer verwarrend kan zijn voor uw gebruikers. Het moet ook zorgvuldig worden gebruikt, zie het antwoord van Siddharth Routhier (sectie “Vind laatste rij in een blad”)
  • Explicietere oplossingen die individuele Cells‘ in een lus controleren, zijn over het algemeen langzamer dan het hergebruiken van een Excel-functie (hoewel dit nog steeds performant kan zijn), maar laten je precies specificeren wat je wilt vinden. Zie mijn oplossingop basis van UsedRangeen VBA-arrays om de laatste cel met gegevens in de gegeven column — het behandelt verborgen rijen, filters, spaties, wijzigt de standaardwaarden voor zoeken niet en is behoorlijk performant.

Welke oplossing u ook kiest, wees voorzichtig

  • om Longte gebruiken in plaats van Integerom de rijnummers op te slaan (om te voorkomen dat je Overflowkrijgt met meer dan 65.000 rijen) en
  • om altijd het werkblad waarmee u werkt te specificeren (bijv. Dim ws As Worksheet ... ws.Range(...)in plaats van Range(...))
  • bij gebruik van .Value(wat een Variantis), vermijd impliciete casts zoals .Value <> ""omdat ze zullen mislukken als de cel een foutwaarde bevat.

Antwoord 6, autoriteit 2%

Ik zou aan het antwoord van Siddarth Rout willen toevoegen dat de CountA-aanroep kan worden overgeslagen door Find een Range-object te laten retourneren in plaats van een rijnummer, en vervolgens het geretourneerde Range-object te testen om te zien of het niets is ( leeg werkblad).

Ik zou ook willen dat mijn versie van een LastRow-procedure een nul retourneert voor een leeg werkblad, dan weet ik dat het leeg is.


Antwoord 7, autoriteit 2%

Ik vraag me af dat niemand dit heeft genoemd, maar de gemakkelijkste manier om de laatst gebruikte cel te krijgen is:

Function GetLastCell(sh as Worksheet) As Range
    GetLastCell = sh.Cells(1,1).SpecialCells(xlLastCell)
End Function

Dit retourneert in wezen dezelfde cel die u krijgt door Ctrl+ Endna het selecteren van Cel A1.

Een waarschuwing: Excel houdt de meest rechtse cel bij die ooit in een werkblad is gebruikt. Dus als u bijvoorbeeld iets invoert in B3en iets anders in H8en later de inhoud van H8verwijdert, drukt u op Ctrl + Endbrengt je nog steeds naar de cel H8. De bovenstaande functie zal hetzelfde gedrag vertonen.


Antwoord 8

sub last_filled_cell()
msgbox range("A65536").end(xlup).row
end sub

Hier is A65536de laatste cel in kolom A. Deze code is getest in Excel 2003.


Antwoord 9

Hoewel deze vraag de laatste rij probeert te vinden met VBA, denk ik dat het goed zou zijn om een ​​matrixformule op te nemen voor de werkbladfunctie, aangezien deze vaak wordt bezocht:

{=ADDRESS(MATCH(INDEX(D:D,MAX(IF(D:D<>"",ROW(D:D)-ROW(D1)+1)),1),D:D,0),COLUMN(D:D))}

Je moet de formule invoeren zonder haakjes en vervolgens op Shift+ Ctrl+ Enterdrukken om er een matrixformule van te maken.

Dit geeft je het adres van de laatst gebruikte cel in de kolom D.


Met dank aan pgsystemtester, dit geeft je het rijnummer van de laatst gebruikte cel:

{=MATCH(INDEX(D:D,MAX(IF(D:D<>"",ROW(D:D)-ROW(D1)+1)),1),D:D,0)}

Antwoord 10

Bijgewerkt eind 2021

Met Excel’s nieuwe berekeningsengine en arrayfunctionaliteit, en Filterfunctie, ik denk dat dit onderwerp nu veel minder omstreden zou moeten zijn en dat de onderstaande opties de beste mix van snelheid, betrouwbaarheid en eenvoud bieden (wat moeilijk te balanceren is gebleken in het verleden, zoals de talrijke berichten hier illustreren).

Ook definieer ik last usedals NIET leegzoals gedefinieerd door de isBlankfunctie.

Excel-formule

Houd er rekening mee dat de filterfunctie het veel eenvoudiger maakt om een ​​laatste cel te krijgen met behulp van de onderstaande formules voor een specifieke rij of kolom (in dit geval Column Aof Row 1):

=MAX(FILTER(ROW(A:A),NOT(ISBLANK(A:A))))
=MAX(FILTER(COLUMN(1:1),NOT(ISBLANK(1:1))))

VBA-functie voor specifiek bereik laatste rij

Met de bovenstaande functie kunnen we het omzetten in een VBA-functie, maar het nog sneller maken door het bereik te beperken, terwijl we de mogelijkheden uitbreiden door meerdere kolommen te maken (dankzij Chris Neilsenvoor directe feedback, tweeken/suggesties). Ik vond ook een enorme snelheidsverbetering door het bereik van elke kolom alleen een bereik te maken met een rij HOGER dan de vorige laatste rij.

Function FindLastRowInRange(someColumns As Range) As Long
Const zFx = "=MAX(FILTER(ROW(????),NOT(ISBLANK(????)),0))"
   Dim tRng As Range, i As Long, tRow As Long, nRng As Range
   With someColumns.Worksheet
      Set tRng = Intersect(someColumns.EntireColumn, .UsedRange)
      For i = 1 To tRng.Columns.Count
         Set pRng = Intersect(tRng.Columns(i), _
         Range(.Rows(FindLastRowInRange + 1), .Rows(.Rows.Count)))
         If Not pRng Is Nothing Then
            tRow = .Evaluate(Replace(zFx, "????", _
               pRng.Address, 1, -1))
            If tRow > FindLastRowInRange Then _
               FindLastRowInRange = tRow
         End If
      Next i
   End With
End Function

VBA-functie voor laatste rij in werkblad

Om het hele werkblad (alle kolommen) te bekijken, raad ik aan een andere VBA-formule te gebruiken die naar de vorige verwijst, maar die een Vluchtige functie. Dit zorgt ervoor dat de formule wordt bijgewerkt met allewijzigingen in een werkblad. Het is duidelijk dat je deze twee formules kunt combineren, maar ik geef er de voorkeur aan het gebruik van vluchtige functies te beperken.

Function FindLastRowInSheet(anywhereInSheet As Range) As Long
      Application.Volatile
      FindLastRowInSheet = FindLastRowInRange(anywhereInSheet.Worksheet.UsedRange)
End Function

Voordelen in vergelijking met andere opties

  • Maakt sommige of ALLE rijen/kolommen in werkblad mogelijk zonder de aanpak te veranderen.
  • Geen mogelijkheid om verborgen rijen te missen, zoals een risico is met xlup
  • Negeert problemen met opgemaakt/gebruikt bereik.
  • Beïnvloedt de instellingen van Findvan de gebruiker niet.
  • Gebruikt werkbladfunctionaliteit die sneller is dan VBA-berekeningen.
  • Geen telcellen (performance hog).

Hopelijk beëindigt dit het debat, maar als iemand hier zwakke punten in vindt, deel het dan alsjeblieft.


Antwoord 11

Ik was op zoek naar een manier om de CTRL+Shift+Endna te bootsen, dus de dotNET-oplossing is geweldig, behalve met mijn Excel 2010 Ik moet een settoevoegen als ik een fout wil vermijden:

Function GetLastCell(sh As Worksheet) As Range
  Set GetLastCell = sh.Cells(1, 1).SpecialCells(xlLastCell)
End Function

en hoe u dit zelf kunt controleren:

Sub test()
  Dim ws As Worksheet, r As Range
  Set ws = ActiveWorkbook.Sheets("Sheet1")
  Set r = GetLastCell(ws)
  MsgBox r.Column & "-" & r.Row
End Sub

Antwoord 12

Sub lastRow()
    Dim i As Long
        i = Cells(Rows.Count, 1).End(xlUp).Row
            MsgBox i
End Sub
sub LastRow()
'Paste & for better understanding of the working use F8 Key to run the code .
dim WS as worksheet
dim i as long
set ws = thisworkbook("SheetName")
ws.activate
ws.range("a1").select
ws.range("a1048576").select
activecell.end(xlup).select
i= activecell.row
msgbox "My Last Row Is " & i
End sub

Antwoord 13

Voor de laatste 3+ jaar zijn dit de functies die ik gebruik voor het vinden van de laatste rij en laatste kolom per gedefinieerde kolom (voor rij) en rij (voor kolom):

Laatste kolom:

Function lastCol(Optional wsName As String, Optional rowToCheck As Long = 1) As Long
    Dim ws  As Worksheet
    If wsName = vbNullString Then
        Set ws = ActiveSheet
    Else
        Set ws = Worksheets(wsName)
    End If
    lastCol = ws.Cells(rowToCheck, ws.Columns.Count).End(xlToLeft).Column
End Function

Laatste rij:

Function lastRow(Optional wsName As String, Optional columnToCheck As Long = 1) As Long
    Dim ws As Worksheet
    If wsName = vbNullString Then
        Set ws = ActiveSheet
    Else
        Set ws = Worksheets(wsName)
    End If
    lastRow = ws.Cells(ws.Rows.Count, columnToCheck).End(xlUp).Row
End Function

Voor het geval van de OP is dit de manier om de laatste rij in kolom Ete krijgen:

Debug.Print lastRow(columnToCheck:=Range("E4:E48").Column)

Laatste rij, lege rijen met gegevens tellen:

Hier kunnen we de bekende Excel-formules, die ons de laatste rij van een werkblad in Excel geven, zonder VBA erbij te betrekken – =IFERROR(LOOKUP(2,1/(NOT(ISBLANK(A:A))),ROW(A:A)),0)

Om dit in VBA te zetten en niets in Excel te schrijven, met behulp van de parameters voor de laatste functies, zou zoiets in gedachten kunnen worden gehouden:

Public Function LastRowWithHidden(Optional wsName As String, Optional columnToCheck As Long = 1) As Long
    Dim ws As Worksheet
    If wsName = vbNullString Then
        Set ws = ActiveSheet
    Else
        Set ws = Worksheets(wsName)
    End If
    Dim letters As String
    letters = ColLettersGenerator(columnToCheck)
    LastRowWithHidden = ws.Evaluate("=IFERROR(LOOKUP(2,1/(NOT(ISBLANK(" & letters & "))),ROW(" & letters & " )),0)")
End Function
Function ColLettersGenerator(col As Long) As String
    Dim result As Variant
    result = Split(Cells(1, col).Address(True, False), "$")
    ColLettersGenerator = result(0) & ":" & result(0)
End Function

Antwoord 14

Laatste rij in een normaal bereik of een tabel (ListObject)

  1. Het vinden van de laatste rij vereist het gebruik van verschillende methoden als het bereik een normaal bereik of een tabel is (Lijstobject).
  2. Het vinden van de laatste rij in tabellen vereist het specificeren van aanvullende parameters (tabelnaam , de relatieve positie van de kolom ten opzichte van de eerste tabelkolom).

Ik heb deze universele functie voor de laatste rij gemaakt, ongeacht het bereiktype. Geef het gewoon welke celverwijzing dan ook en het zal de laatste rij retourneren.
Geen gedoe om bereikkenmerken te kennen, vooral als uw bereiken soms een normaal bereik zijn en soms een ListObject.
Het gebruik van een normale bereikmethode op een tabel kan verkeerde resultaten opleveren.
Natuurlijk kun je van tevoren plannen en elke keer de juiste methode gebruiken, maar waarom zou je je druk maken als je een universele functie kunt gebruiken?

Sub RunMyLastRow()
Dim Result As Long
Result = MyLastRow(Worksheets(1).Range("A1"))
End Sub
   Function MyLastRow(RefrenceRange As Range) As Long
    Dim WS As Worksheet
    Dim TableName As String
    Dim ColNumber As Long
    Dim LastRow As Long
    Dim FirstColumnTable As Long
    Dim ColNumberTable As Long
    Set WS = RefrenceRange.Worksheet
    TableName = GetTableName(RefrenceRange)
    ColNumber = RefrenceRange.Column
    ''If the table (ListObject) does not start in column "A" we need to calculate the 
    ''first Column table and how many Columns from its beginning the Column is located.
    If TableName <> vbNullString Then
     FirstColumnTable = WS.ListObjects(TableName).ListColumns(1).Range.Column
     ColNumberTable = ColNumber - FirstColumnTable + 1
    End If 
    If TableName = vbNullString Then
    LastRow = WS.Cells(WS.Rows.Count, ColNumber).End(xlUp).Row
    Else
    LastRow = WS.ListObjects(TableName).ListColumns(ColNumberTable).Range.Find( _
               What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
    End If
    MyLastRow = LastRow
    End Function
   ''Get Table Name by Cell Range
    Function GetTableName(RefrenceRange As Range) As String
        If RefrenceRange.ListObject Is Nothing Then
            GetTableName = vbNullString
        Else
            GetTableName = RefrenceRange.ListObject.Name
        End If
    End Function

Other episodes