Letzte Zeile/Spalte eines Tabellenblatts
Sie brauchen wahrscheinlich öfter einmal die Position, den numerischen Wert der letzten beschriebenen Spalte oder Zeile einer Tabelle (nicht direkt den Inhalt). Prinzipiell ist das immer dann der Fall, wenn Sie unterhalb der letzten Zeile oder rechts der letzten Spalte neue Werte einfügen wollen. Viele Wege führen zum Ziel, gute und weniger gute …
Bitte nicht so:
Aus Unkenntnis manchen Seiteneffekts wird oft folgendes verwendet:
x = ActiveCell.SpecialCells(xlLastCell).Column y = ActiveCell.SpecialCells(xlLastCell).Row
Diese Lösung ist aber sehr ungenau, sie liefert in vielen Fällen falsche Ergebnisse. Um das zu testen, machen Sie bitte einmal folgendes:
- Tragen Sie einige Werte in eine Tabelle ein.
- Dann geben Sie in eine Zelle, die um mindestens 1 Zeile und Spalte weiter nach rechts und und auch nach unten verschoben ist als die bisherige äußerste Position einen beliebigen Wert ein.
- Klicken Sie nun in eine andere Zelle.
- Löschen Sie jetzt die eben eingegebenen Daten aus der „ausgegliederten” Zelle.
- Führen Sie nun zur Kontrolle den folgenden (extrem einfach gehaltenen) Code aus:
Sub LetzteZelle() Dim x, y x = ActiveCell.SpecialCells(xlLastCell).Column y = ActiveCell.SpecialCells(xlLastCell).Row MsgBox "Spalte " & x & " Zeile " & y End Sub
Hier der Code (als gepackte Textdatei) zum Kopieren und Einfügen in den VBA-Editor. Diese „Unart” von Excel wird wohl nie beseitigt werden. Noch unangenehmer (weil schwerer zu finden) ist es, wenn eine Zelle außerhalb des eigentlichen Datenbereichs eine besondere Formatierung jedoch keinen Wert hat. Diese „falsche” Zelle wird immer „gefunden”, auch wenn Sie die Tabelle unter einem anderen Namen speichern.
Sondern beispielsweise so:
Ein korrektes Ergebnis erhalten Sie mit diesen beiden Code-Zeilen:
LastRow = ActiveSheet.Cells(Rows.Count, Spalte).End(xlUp).Row
und / bzw.
LastCol = ActiveSheet.Cells(Zeile, Columns.Count).End(xlToLeft).Column
wobei Sie statt Spalte bzw. Zeile den numerischen Wert der Spalte oder Zeile eingeben. Die Spalte A hat dann den numerischen Wert 1, Spalte B hat die 2, usw. Das Ergebnis bezieht sich dann stets exakt auf die Spalte/Zeile, die Sie angegeben haben. Noch einmal mit anderen Worten: Es wird nur die angegebene Zeile bzw. Spalte ausgewertet; selbst wenn andere Zeilen bzw. Spalten weiter unten oder weiter rechts noch Eingaben haben, werden diese nicht berücksichtigt.
Und mit „Notbremse”:
Der obige Code reicht im Normalfall vollkommen aus. Sollte aber auch nur die geringste „Gefahr” bestehen, dass auch die letzte Zeile oder Spalte des Tabellenblatt beschrieben ist, dann sind Sie mit diesen Code-Zeilen auf der sicheren Seite (bezieht sich auf Spalte A bzw. Zeile 1):
LastRow = IIf(IsEmpty(ActiveSheet.Cells(Rows.Count, 1)), _ ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row, _ ActiveSheet.Rows.Count)
bzw. zur Feststellung der letzten Spalte:
LastCol = IIf(IsEmpty(ActiveSheet.Cells(1, Columns.Count)), _ ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Column, _ ActiveSheet.Cells(1, Columns.Count).Column)
Für die letzte Zeile geht es auch so, wenn Sie die Alphanumerischen Angaben der Spalte und nicht die (rein) numerischen verwenden wollen:
LastRow = IIf(IsEmpty(ActiveSheet.Cells(Rows.Count, "A")), _ ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row, _ ActiveSheet.Rows.Count)
Etwas professioneller können Sie diese beiden Codeblöcke auch so schreiben:
With ActiveSheet Lastrow = IIf(IsEmpty(.Cells(Rows.Count, 1)), _ .Cells(Rows.Count, 1).End(xlUp).Row, _ .Rows.Count) End With With ActiveSheet LastCol = IIf(IsEmpty(.Cells(1, Columns.Count)), _ .Cells(1, Columns.Count).End(xlToLeft).Column, _ .Cells(1, Columns.Count).Column) End With 'Bei GEMEINSAMER Variablenzuweisung etwas kürzer: With ActiveSheet LastRow = IIf(IsEmpty(.Cells(Rows.Count, 1)), _ .Cells(Rows.Count, 1).End(xlUp).Row, _ .Rows.Count) LastCol = IIf(IsEmpty(.Cells(1, Columns.Count)), _ .Cells(1, Columns.Count).End(xlToLeft).Column, _ .Cells(1, Columns.Count).Column) End With
Auch hier gibt es natürlich die Möglichkeit, die Spaltenbezeichnung als Zeichenkette (String) in den Code einzugeben.
Wollen Sie ‑ähnlich wie beim ersten Versuch- den entsprechenden Wert der kompletten Tabelle ermitteln, dann sind folgende Zeilen zielführend:
LastRowAll =Cells.Find(What:="*", _ SearchOrder:=xlByRows, _ SearchDirection:=xlPrevious).Row
sowie
LastColAll =Cells.Find(What:="*", _ SearchOrder:=xlByColumns, _ SearchDirection:=xlPrevious).Column
Als Funktion universell einsetzbar
Ich ziehe es vor, diese beiden Routinen in eine Funktion auszulagern, damit ich von verschiedenen Prozeduren oder anderen Funktionen darauf zugreifen kann. Wichtig: Was Sie hier auf dieser Seite sehen, ist mehr oder weniger nur das Prinzip. Rudimentär läuft das auch, wenn die Funktionen im gleichen Modul wie die Prozedur stehen. Professioneller und wesentlich sicherer ist der Code, wie er in der Muster-Datei bzw. den Code-Files abgelegt ist. Unsere Empfehlung: Unbedingt dort zumindest einmal reinschauen!
Public Function LastRowAll(Optional wks As Variant) As Long If IsMissing(wks) Then set wks = ActiveSheet LastRowAll = wks.Cells.Find(What:="*", _ SearchOrder:=xlByRows, _ SearchDirection:=xlPrevious).Row End Function Public Function LastColAll(Optional wks As Variant) As Long If IsMissing(wks) Then set wks = ActiveSheet LastColAll = wks.Cells.Find(What:="*", _ SearchOrder:=xlByColumns, _ SearchDirection:=xlPrevious).Column End Function
Und nicht nur der Komplettheit wegen auch noch die beiden anderen Funktionen für die einzelnen Spalten/Zeilen:
Public Function LastRow(Optional Spalte, Optional Wks) As Long Dim AnzZe As Long If IsMissing(Spalte) Then Spalte = 1 If Spalte = 0 Then Spalte = 1 If IsMissing(Wks) Then Set Wks = ActiveSheet With Wks AnzZe = .Rows.Count LastRow = IIf(IsEmpty(.Cells(AnzZe, Spalte)), _ .Cells(Rows.Count, Spalte).End(xlUp).Row, AnzZe) End With End Function Public Function LastCol(Optional Zeile, Optional Wks) As Long Dim AnzSp As Integer AnzSp = Columns.Count If IsMissing(Zeile) Then Zeile = 1 If Zeile = 0 Then Zeile = 1 If IsMissing(Wks) Then Set Wks = ActiveSheet With Wks AnzSp = .Columns.Count LastCol = IIf(IsEmpty(.Cells(Zeile, _ AnzSp).End(xlToLeft).Column), _ .Cells(Zeile, AnzSp).End(xlToLeft).Column, AnzSp) End With End Function
Wichtiger Hinweis: Vielfach wird ja die letzte Zeile gesucht, um die erste freie Zeile zu bestimmen. In den allermeisten Fällen wird auch der obige Code vollkommen ausreichen, wenn Sie (beispielsweise)
FirstFreeRow = LastRow + 1
im Code verwenden. Wenn Sie aber „Auf Nummer Sicher” gehen wollen, also alle erdenklichen Fehler erst gar nicht zulassen möchten, dann bietet sich die Feststellung der ersten freien Zeile so an:
If LastRow = ActiveSheet.Rows.Count Then MsgBox "Es ist keine Zeile mehr frei" Exit Sub End If
Dann wird der Ablauf des Programms „sauber” mit einer Fehlermeldung beendet und eigentlich weiß dann jeder User, woran es wirklich liegt. – Diesen Code biete ich nicht zum Download an, die vier kurzen Zeilen lassen sich ganz gut per C:P einfügen oder schnell mal abtippen.
Download-Übersicht
In diesem Beitrag werden Ihnen eine oder mehrere Files zum Download angeboten. In der folgenden Tabelle ist jede Datei mit verschiedenen Informationen aufgeführt. Ein Klick auf den Link in der ersten (linken) Spalte startet den Download von unserem Server.
Hinweise:
- Sehr viele der hier angebotenen Dateien sind als *.zip gepackt. Das geschieht nicht aus Gründen der Dateigröße sondern einerseits wegen des Komforts beim herunter laden vom Server und andererseits zur Datensicherheit.
-
Teilweise sind in gepackten Code-Files mehrere Einzeldateien enthalten. Es gelten dann die gleichen Regeln wie bei einzeln
angebotenen Downloads. Typischerweise haben die ursprünglichen Files diese Endung:
- *.txt : Dateien im reinen Textformat. Öffnen Sie diese Formate in einem reinen Text-Editor wie beispielsweise Notepad oder (vorzugsweise) Notepad++ [u.a. hier in Deutsch] (aber nie in einer Textverarbeitung wie Word, Writer, …). Kopieren Sie den Code-Text und fügen Sie ihn dann im VBA-Editor a passender Stelle ein.
- *.bas : Typischerweise sind das exportierte Funktionen eines allgemeinen Moduls. Das Einfügen im VBA-Editor gestaltet sich recht einfach: Datei | Datei importieren oder StrgM und automatisch wird alles für Sie erledigt. Wirklich alles.
- *.cls : Dieses sind i.d.R. exportierte Inhalte eines Moduls einer Tabelle oder einer Mappe. Das Einfügen im VBA-Editor gestaltet sich gleichermaßen einfach wie vor: Datei | Datei importieren oder StrgM und automatisch wird alles für Sie erledigt. Wirklich alles.
- *.xls, *.xlsx, *.xlsm : Excel-Dateien in verschiedenen Versionen. In den meisten Fällen sind die Excel-Files aber nicht gepackt sondern liegen in ihrer nativen Form vor.
- Verschiedene Browser zeigen beim Herunterladen der gepackten Basic – Datei eine Warnmeldung, dass die Datei ungewöhnlich sei und/oder Schaden anrichten könne. Wir versichern Ihnen, dass die Datei beim hoch laden absolut frei von Schaden hervorrufenden Elementen war. Zu Kontrollzwecken steht Ihnen noch eine Datei mit der CRC-Quersumme (letzte Spalte) zur Verfügung. Im Zweifel steht Ihnen immer noch die gepackte und Code-seitig identische Text-Datei zur Verfügung. Um solch eine Warnung zu überlisten, müssten wir die *.zip noch verschlüsseln und Sie hätten dann beim Entpacken wegen des Passwortes mehr Aufwand. Das wollen wir umgehen.
Selbstredend können Sie dann daraus auch ein Add-In erstellen, damit diese Funktionalität in allen Workbooks auf Ihrem Rechner zur Verfügung steht. Auf Wunsch senden wir Ihnen gerne das fertige Add-In gegen eine Aufwandsentschädigung zu, einfach eine Mail senden …
Hinweis: Diese Thematik wird in diesem Blog noch einmal hier mit ähnlicher Problemstellung diskutiert.
[NachObenLetzte Verweis=„T&T, Codeschn. LetzteZeile/Spalte”]