🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA Letzte Zeile in Excel — Das echte Ende Ihrer Daten finden (und die Falle in jeder Methode)

|

VBA Letzte Zeile in Excel — Das echte Ende Ihrer Daten finden (und die Falle in jeder Methode)

TL;DR — Hören Sie auf, Range("A1:A100") fest zu verdrahten. Ihre Daten wachsen und schrumpfen, finden Sie ihre Grenze also zur Laufzeit. Das kanonische Idiom ist Cells(Rows.Count, "A").End(xlUp).Row — es simuliert das Drücken von Strg + ↑ vom untersten Ende der Spalte. Nutzen Sie Rows.Count, niemals ein fest verdrahtetes 65536. Es gibt vier Wege zu fragen „wo enden die Daten?", und jeder beantwortet eine leicht andere Frage: .End(xlUp) findet die letzte nicht-leere Zelle in einer Spalte, .End(xlDown) stoppt an der ersten Lücke, .UsedRange meldet zu viel und .Find ist der einzige wirklich lückensichere Weg. Wählen Sie die falsche Methode, verarbeiten Sie die falschen Zeilen — ohne dass ein Fehler Sie warnt.

Die letzte Zeile zu finden ist das Häufigste, was ein Makro erledigen muss, bevor es schleifen, kopieren, sortieren oder löschen kann. Es ist auch die Stelle, an der Anfänger die fragilste Zeile der ganzen Prozedur schreiben: ein fest verdrahtetes A2:A500. Fügen Sie eine Zeile hinzu, und das Makro übersieht sie; löschen Sie Zeilen, und es verarbeitet Hunderte von Leerzeilen. Echtes VBA nimmt die Größe der Daten nie an — es misst sie.

Was Sie lernen

  • Das kanonische Idiom Cells(Rows.Count, "A").End(xlUp).Row, Stück für Stück entschlüsselt
  • Warum 65536 eine Tretmine ist und Rows.Count die Lösung
  • Der Fehlermodus, der sich in jeder der vier Methoden versteckt (.End(xlUp), .End(xlDown), .UsedRange, .Find)
  • Wie Sie die letzte Spalte finden, nicht nur die letzte Zeile
  • Wann Lücken in Ihren Daten bedeuten, dass Sie von .End auf .Find umsteigen müssen

Das mentale Modell: Ihre Daten haben eine Grenze, und Excel gibt sie Ihnen nicht

Ein Arbeitsblatt ist ein Raster mit einer Million Zeilen. Ihre Daten belegen irgendein Rechteck darin, aber Excel führt keine ordentliche „letzte Zeile"-Eigenschaft, die Sie einfach auslesen könnten. Sie müssen also bis an die Grenze laufen und fragen, wo Sie gelandet sind. Jede zuverlässige Technik ist eine Variante von „Starten Sie an einer Stelle, von der Sie wissen, dass sie hinter den Daten liegt, und springen Sie dann zurück zum letzten Eintrag, der tatsächlich vorhanden ist".

Das Bild vor dem inneren Auge für das kanonische Idiom ist eine Person, die ganz unten in einer Spalte steht und Strg + ↑ drückt: Der Cursor fliegt nach oben und stoppt auf der letzten Zelle mit Inhalt. Genau das macht .End(xlUp) im Code.

Sub FindLastRow()
    Dim ws As Worksheet
    Set ws = ActiveSheet

    Dim lastRow As Long
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

    Debug.Print "Last row with data in column A: " & lastRow
End Sub

Lesen Sie es von innen nach außen: ws.Rows.Count ist die Anzahl der Zeilen auf dem Blatt (1.048.576 im modernen Excel). Cells(that, "A") ist die unterste Zelle der Spalte A. .End(xlUp) springt hoch zur letzten nicht-leeren Zelle. .Row liest deren Zeilennummer ab. Diese eine Zeile ist das Arbeitspferd — aber nur, wenn Sie die Falle verstehen, die sie mit sich bringt.

Die Regel, die Sie vor dem schlimmsten Letzte-Zeile-Bug bewahrt: niemals 65536 fest verdrahten

Ein Jahrzehnt lang schrieben Tutorials Cells(65536, 1).End(xlUp).Row, weil 65.536 die letzte Zeile des alten .xls-Formats war. Moderne .xlsx-Blätter haben 1.048.576 Zeilen. Wenn Ihre Daten über Zeile 65.536 hinausreichen und Sie Ihren Sprung nach oben bei 65.536 beginnen, starten Sie oberhalb eines Teils Ihrer Daten und liefern stillschweigend eine letzte Zeile zurück, die zu klein ist — was Ihre Schleife mitten in der Tabelle abschneidet.

' FRAGIL — startet oberhalb aller Daten unterhalb von Zeile 65536
lastRow = Cells(65536, 1).End(xlUp).Row

' KORREKT — startet immer vom echten unteren Rand DIESES Blatts
lastRow = Cells(Rows.Count, 1).End(xlUp).Row

Rows.Count liest die tatsächliche Zeilenzahl des Blatts, auf dem der Code läuft — es ist damit zukunfts- und versionssicher. Es gibt kein Szenario, in dem das feste Verdrahten der Zahl besser ist. Machen Sie Cells(Rows.Count, col) zum Reflex.

Die Regel, die jede Methode mit ihrem Fehlermodus verknüpft

Hier ist der Teil, den jedes Tutorial überspringt: Die vier gängigen Methoden liefern nicht dieselbe Antwort, weil sie unterschiedliche Fragen beantworten. Lernen Sie den Fehlermodus jeder einzelnen, und Sie wissen immer, zu welcher Sie greifen müssen.

.End(xlUp) — letzte nicht-leere Zelle in einer Spalte. Der Standard. Sein blinder Fleck: Es betrachtet nur eine Spalte. Wenn Sie eine Spalte wählen, die eine Lücke hat, in der die letzte Zeile leer ist (etwa der Name in Zeile 500 ist leer, der Betrag aber nicht), halten Sie zu früh an. Wählen Sie eine Spalte, die auf jeder Datenzeile garantiert befüllt ist — eine ID oder einen Schlüssel — oder finden Sie die letzte Zeile über die gesamte Tabelle mit .Find.

.End(xlDown) — erste Lücke von oben. Das ist Strg + ↓ ab Zeile 1. Es findet nicht die letzte Zeile; es findet die Zeile unmittelbar vor der ersten leeren Zelle. Eine einzige leere Zelle mitten in Ihrer Spalte kappt Sie auf den obersten Block. Verwenden Sie .End(xlDown) niemals, um das Ende der Daten zu finden — nur, um das Ende eines ununterbrochenen Blocks zu finden.

' A1:A10 enthält Daten, A6 ist leer, A7:A10 enthält weitere Daten
Cells(1, 1).End(xlDown).Row     ' -> 5   (hält an der Lücke — FALSCH für „letzte Zeile")
Cells(Rows.Count, 1).End(xlUp).Row  ' -> 10  (echte letzte Zeile — RICHTIG)

.UsedRange — Excels zwischengespeicherter Umgrenzungsrahmen. ws.UsedRange sind nicht Ihre Daten; es ist jede Zelle, die Excel jemals angefasst hat, einschließlich Zellen, die nur Formatierung tragen, und es schrumpft nicht, wenn Sie Zeilen löschen — erst wenn die Arbeitsmappe gespeichert oder neu berechnet wird. Es meldet zu viel, sodass eine Schleife über UsedRange sich durch Hunderte von Phantomzeilen quälen kann. Es beginnt zudem nicht zwangsläufig bei Zeile 1 (siehe FAQ). Behandeln Sie UsedRange als „ungefähr das ganze Blatt", niemals als präzise Nummer der letzten Zeile.

.Find — die einzige lückensichere Methode. Rückwärts nach der letzten Zelle zu suchen, die irgendetwas, irgendwo auf dem Blatt enthält, ist immun gegen interne Leerstellen und gegen die Spalte, die Sie wählen:

Function LastDataRow(ws As Worksheet) As Long
    Dim c As Range
    Set c = ws.Cells.Find(What:="*", After:=ws.Cells(1, 1), _
                          LookIn:=xlFormulas, SearchOrder:=xlByRows, _
                          SearchDirection:=xlPrevious)
    If c Is Nothing Then
        LastDataRow = 0            ' leeres Blatt
    Else
        LastDataRow = c.Row
    End If
End Function

.Find ist umständlich, und Sie müssen den Nothing-Fall behandeln (ein leeres Blatt), aber es ist die richtige Antwort, wenn Ihre Daten ausgefranste Ränder oder interne Lücken haben. LookIn:=xlFormulas findet Zellen mit einer Formel, selbst wenn diese aktuell zu "" ausgewertet wird; xlValues ignoriert solche — wählen Sie bewusst.

Die Ermessensentscheidung: welche Methode wann

  • Saubere einspaltige Liste oder eine Tabelle mit einer soliden SchlüsselspalteCells(Rows.Count, keyCol).End(xlUp).Row. Schnell, lesbar, korrekt.
  • Daten mit internen Leerzeilen oder einem ausgefransten rechten Rand.Find(What:="*", SearchDirection:=xlPrevious). Lückensicher.
  • „Wie groß ist ungefähr alles auf diesem Blatt, damit ich es leeren kann".UsedRange. Das Zuviel-Melden ist harmlos, wenn Sie ohnehin löschen.
  • Niemals .End(xlDown) für die letzte Zeile verwenden und niemals UsedRange.Rows.Count lesen, als wäre es die Nummer der letzten Zeile.

Auch die letzte Spalte finden

Derselbe Sprung-Trick funktioniert auch seitwärts. Beginnen Sie an der ganz rechten Zelle Ihrer Kopfzeile und drücken Sie im Code Strg + ←:

Dim lastCol As Long
lastCol = Cells(1, Columns.Count).End(xlToLeft).Column

Mit beiden Zahlen können Sie den exakten Datenbereich bauen, ohne irgendetwas fest zu verdrahten:

Dim rng As Range
Set rng = ws.Range(ws.Cells(1, 1), ws.Cells(lastRow, lastCol))

Genau darum geht es: Sobald Sie die Ränder finden können, tippen Sie nie wieder eine feste Adresse. Um einen Bereich zu bauen, der die Kopfzeile überspringt, kombinieren Sie dies mit Offset und Resize; um den zusammenhängenden Block in einem Aufruf zu greifen, siehe UsedRange vs. CurrentRegion.

Wie ExcelMaster hilft

Fast jede „Wie finde ich die letzte Zeile"-Frage ist in Wahrheit ein Schritt zu einem größeren Ziel: diese Spalte durchlaufen und Duplikate markieren, neue Zeilen auf ein anderes Blatt kopieren, nach Gruppe summieren. ExcelMaster nimmt dieses Ziel in einfachem Deutsch entgegen — „Kopiere für jede Zeile in der Bestelltabelle die unerledigten auf das Blatt Backlog" — und schreibt die Bereichsarithmetik für Sie, findet die Ränder der Daten auf die robuste Weise, statt eine feste Größe anzunehmen.

Sie werden .End(xlUp) weiterhin von Hand schreiben, wenn es in einem geplant laufenden Makro steckt. Aber für die alltägliche „Verarbeite einfach die Zeilen, die heute da sind"-Aufgabe schlägt das Beschreiben des Ergebnisses das jedes Mal korrekte Hinbekommen von Rows.Count und Lückenbehandlung.

Häufig gestellte Fragen

Was ist der beste Weg, die letzte Zeile in VBA zu finden?

Bei einer Tabelle mit einer zuverlässig befüllten Schlüsselspalte nehmen Sie Cells(Rows.Count, keyColumn).End(xlUp).Row. Es ahmt Strg + ↑ vom unteren Blattrand nach und ist schnell und lesbar. Haben Ihre Daten interne Leerzeilen oder einen ausgefransten Rand, nehmen Sie stattdessen Cells.Find(What:="*", SearchDirection:=xlPrevious).Row, weil .End an einer Lücke anhalten kann.

Warum sollte ich Rows.Count statt 65536 verwenden?

65536 war die letzte Zeile des alten .xls-Formats. Moderne .xlsx-Blätter haben 1.048.576 Zeilen, sodass ein Sprung nach oben, der bei 65.536 beginnt, oberhalb aller Daten unterhalb dieses Punktes startet und eine zu kleine letzte Zeile zurückgibt. Rows.Count spiegelt immer die tatsächliche Größe des aktuellen Blatts wider.

Warum liefert UsedRange die falsche letzte Zeile?

UsedRange ist ein zwischengespeicherter Umgrenzungsrahmen jeder Zelle, die Excel jemals angefasst hat, einschließlich reiner Formatierungszellen, und er schrumpft beim Löschen von Daten erst, wenn die Datei gespeichert wird. Er beginnt außerdem möglicherweise nicht bei Zeile 1, weshalb UsedRange.Rows.Count eine Anzahl ist, keine Nummer der letzten Zeile. Nehmen Sie .End(xlUp) oder .Find für eine präzise letzte Zeile.

Wie finde ich die letzte Spalte in VBA?

Spiegeln Sie das Letzte-Zeile-Idiom seitwärts: Cells(1, Columns.Count).End(xlToLeft).Column. Es springt von der ganz rechten Zelle der Kopfzeile zurück zur letzten Spalte mit Inhalt.

Wie finde ich die letzte Zeile, wenn die Spalte Leerstellen hat?

.End(xlUp) betrachtet nur eine Spalte, sodass eine Leerstelle in der letzten Datenzeile dieser Spalte es zu früh anhalten lässt. Richten Sie es entweder auf eine Spalte, die immer befüllt ist (eine ID), oder nutzen Sie Cells.Find(What:="*", SearchDirection:=xlPrevious).Row, das die letzte befüllte Zelle irgendwo auf dem Blatt findet, unabhängig von Lücken.

Getestet in

Getestet in: Excel 365 (Windows 11), VBA 7.1 — zuletzt geprüft am 30.07.2026.

Verwandte Anleitungen: VBA Offset · VBA UsedRange vs. CurrentRegion · VBA Range · VBA For-Schleife