Excel VBA Makro Sammeltabelle erstellen
Hallo zusammen,
ich stehe vor einem für meine Begriffe hochkomplexen Makroproblem.
Das Makro soll Daten aus unzähligen txt-Dateien importieren, daraus eine Sammeltabelle erstellen und nach bestimmten Suchkriterien aus dieser erstellen Sammeltabelle Übereinstimmungen in 3 anderen Dateien suchen, um aus diesen weitere Daten in die erstellte Sammeltabelle (natürlich an die richtigen Positionen) zu kopieren.
In einem Ordner "Textdateien" auf der C: Platte befinden sich unzählige Unterordner wobei sich in jedem dieser Ordner unter anderem auch eine txt-Datei befindet. All dieser txt-Dateien ähneln sich im Aufbau, sodass nach dem importieren (als Spaltentrennung soll ein : gelten) einer txt-Datei in Excel (2003) die Zellen A1 - B25 mit Daten gefüllt sind. Ich benötige dann die Daten aus den Zellen B1, B2, B4, B5, B6, B7 und B11 welche in meine Sammeltabelle in die Spalten A-G (für jede txt-Datei eine Zeile, sind im mom ca 100 Unterordner und somit 100 txt-Dateien und werden immer mehr) übernommen werden sollen. Wenn all diese Daten in die nun neu entstandene Sammeltabelle aufgenommen sind, müssten sich in der Spalte B nun Teilernummern befinden. Nach diesen Teilernummern müsste das Makro nun in 3 weiteren im sich im Aufbau ähnlichen Dateien, (z. Bsp.: "Datei1","Datei2","Datei3") wobei sich die Teilenummer immer in der Spalte A befindet, suchen und bei einem Treffer die Daten aus den Zellen B - H der entsprechenden Datei und Trefferzeile in meine Sammeltabelle in die Spalten H - N in die entsprechende Zeile kopieren.
Ich hoffe ich konnte das Problem bzw die Anforderung an das Makro anschaulich genug schildern...ist nicht immer so leicht ohne Anschauungsmaterial.
Die Frage für mich ist, ob das per Makro überhaupt lösbar ist und ob es sich alles in einem einzigen Makro verwirklichen lässt, oder ob man das in 2 Makros verpacken müsste. Für eure Hilfe und über eure Anregungen würde ich mich sehr freuen.
Bis dahin verbleibe ich mit vielen Grüßen
Rio
ich stehe vor einem für meine Begriffe hochkomplexen Makroproblem.
In einem Ordner "Textdateien" auf der C: Platte befinden sich unzählige Unterordner wobei sich in jedem dieser Ordner unter anderem auch eine txt-Datei befindet. All dieser txt-Dateien ähneln sich im Aufbau, sodass nach dem importieren (als Spaltentrennung soll ein : gelten) einer txt-Datei in Excel (2003) die Zellen A1 - B25 mit Daten gefüllt sind. Ich benötige dann die Daten aus den Zellen B1, B2, B4, B5, B6, B7 und B11 welche in meine Sammeltabelle in die Spalten A-G (für jede txt-Datei eine Zeile, sind im mom ca 100 Unterordner und somit 100 txt-Dateien und werden immer mehr) übernommen werden sollen. Wenn all diese Daten in die nun neu entstandene Sammeltabelle aufgenommen sind, müssten sich in der Spalte B nun Teilernummern befinden. Nach diesen Teilernummern müsste das Makro nun in 3 weiteren im sich im Aufbau ähnlichen Dateien, (z. Bsp.: "Datei1","Datei2","Datei3") wobei sich die Teilenummer immer in der Spalte A befindet, suchen und bei einem Treffer die Daten aus den Zellen B - H der entsprechenden Datei und Trefferzeile in meine Sammeltabelle in die Spalten H - N in die entsprechende Zeile kopieren.
Ich hoffe ich konnte das Problem bzw die Anforderung an das Makro anschaulich genug schildern...ist nicht immer so leicht ohne Anschauungsmaterial.
Die Frage für mich ist, ob das per Makro überhaupt lösbar ist und ob es sich alles in einem einzigen Makro verwirklichen lässt, oder ob man das in 2 Makros verpacken müsste. Für eure Hilfe und über eure Anregungen würde ich mich sehr freuen.
Bis dahin verbleibe ich mit vielen Grüßen
Rio
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 172444
Url: https://administrator.de/forum/excel-vba-makro-sammeltabelle-erstellen-172444.html
Ausgedruckt am: 18.04.2025 um 16:04 Uhr
14 Kommentare
Neuester Kommentar
Moin Rio1980,
Ich sach' mal so:
Für mich ist noch gar nicht die Phase erreicht, in der ich mir zutrauen würde zu sagen
Ein, zwei Punkte an dem Gesamtplan würde ich gern noch mal etwas trennschärfer formuliert haben wollen,
i.e. von "unzähligen" Unterordnern und unzähligen Input-Textdateien wissen wir ja jetzt, aber
Diese Rahmenparameter wären für mich schon wesentlich, ehe ich mich auf die Suche nach dem richtigen Werkzeug oder Schnitzmesser mache.
Grüße
Biber
Die Frage für mich ist, ob das per Makro überhaupt lösbar ist und ob es sich alles in einem einzigen Makro verwirklichen lässt, oder ob man das in 2 Makros verpacken müsste
Ich sach' mal so:
Für mich ist noch gar nicht die Phase erreicht, in der ich mir zutrauen würde zu sagen
"Nimm einen 10er Ringschlüssel und einen Kreuzschlitzschraubendreher mit Bambusgriff, der Rest ergibt sich dann von allein."
Ein, zwei Punkte an dem Gesamtplan würde ich gern noch mal etwas trennschärfer formuliert haben wollen,
i.e. von "unzähligen" Unterordnern und unzähligen Input-Textdateien wissen wir ja jetzt, aber
- die Zieldimensionen sind EINE Exceltabelle mit EINEM Sheet ??
- oder mit einem Sheet pro Importiere-mir-alle-Daten-Lauf?
- oder ein Excelsheet pro Woche?
- Ist es eine einmalige oder einer regelmäßige Aktion, passiert es täglich, stündlich oder immer zur Grammy-Verleihung?
- Soll, muss oder darf der Import manuell gestartet werden oder jeden Freitag mittag automatisch?
- WTAF sind denn die "bestimmten Kriterien", nach denen da irgendwas zusammengeharkt werden soll? Stehen die auch in einer CSV-Datei oder "weiss" das Makro diese Kriterien oder gibt der/die UserIn dat ein?
Diese Rahmenparameter wären für mich schon wesentlich, ehe ich mich auf die Suche nach dem richtigen Werkzeug oder Schnitzmesser mache.
Grüße
Biber
Hallo Rio1980 und Biber!
Um mal zu sehen, ob ich einige Antworten auf Bibers Fragen erraten habe, ein [Edit] erweiterter [/Edit] Versuch, die vorgegebenen Daten einzulesen:
Hinsichtlich "Datei1" bis "Datei3" wurde unterstellt, dass
Grüße
bastla
[Edit] "Nachschlagen" in den Dateien "Datei1" bis "Datei3" sowie Löschen (alter Daten) der Zieltabelle hinzugefügt [/Edit]
Um mal zu sehen, ob ich einige Antworten auf Bibers Fragen erraten habe, ein [Edit] erweiterter [/Edit] Versuch, die vorgegebenen Daten einzulesen:
Sub Importieren()
Basis = "C:\Textdateien"
Typ = "txt" 'Dateityp der zu verarbeitenden Dateien in Kleinbuchstaben
Dateien = Array("C:\Datei1.txt", "C:\Datei2.txt", "C:\Datei3.txt")
Adressen = Array(1, 2, 4, 5, 6, 7, 11) 'da alle Werte in Spalte B stehen, nur die Zeilennummern
SchlSpalte = 2 'Spalte B = Schlüsselspalte für Suche in den Dateien
Delim = ":" 'Trennzeichen
AbZeile = 2 'ab dieser Zeile werden die Werte in die Zieltabelle geschrieben
AbSpalte = 1 'Spalte A; ab dieser Spalte werden die Werte in die Zieltabelle geschrieben
MaxFeld = UBound(Adressen) 'höchster Index in der Adressentabelle (= Anzahl der Felder - 1)
Dim Daten()
Set fso = CreateObject("Scripting.FileSystemObject")
Set d = CreateObject("Scripting.Dictionary")
For Each Datei In Dateien 'alle Dateien in Dictionary einlesen
Zeilen = Split(fso.OpenTextFile(Datei).ReadAll, vbCrLf) 'in Zeilenarray einlesen
For i = 0 To UBound(Zeilen) 'alle Zeilen durchgehen
Zeile = Trim(Zeilen(i)) 'ev leading/trailing blanks entfernen
If Zeile <> "" Then 'keine leere Zeile verarbeiten
Schl = Split(Zeile, Delim)(0) 'Schlüssel ist erstes Feld
If Not d.Exists(Schl) Then 'noch kein Datensatz mit diesem Schlüssel vorhanden
Werte = Split(Replace(Zeile, Schl & Delim, "", 1, 1), Delim) 'Werte (erst ab 2. Spalte) in Array übernehmen und ...
d.Add Schl, Werte '... dieses im Dictionary zum Schlüssel ablegen
Else 'Schlüssel gab es schon
MsgBox Schl & " ist bereits vorhanden!", vbCritical
'### weitere Vorgangsweise? ###
End If
End If
Next
Next
Zeile = AbZeile
Cells(Zeile, AbSpalte).Select 'Startzelle für Daten markieren und ...
Range(Selection, ActiveCell.SpecialCells(xlLastCell)).ClearContents '... ab hier Inhalte löschen
For Each Ordner In fso.GetFolder(Basis).SubFolders 'alle Unterordner des Basisordners durchgehen
For Each Datei In fso.GetFolder(Ordner).Files 'alle Dateien des jeweiligen Unterordners durchgehen ...
If LCase(fso.GetExtensionName(Datei.Name)) = Typ Then '... und nur solche des vorgegebenen Typs verarbeiten
Zeilen = Split(Datei.OpenAsTextStream.ReadAll, vbCrLf) 'alle Zeilen der Datei in Array einlesen
ReDim Daten(MaxFeld)
For i = 0 To MaxFeld 'alle Feldwerte lt Adressentabelle ermitteln
Daten(i) = Split(Zeilen(Adressen(i) - 1), Delim)(1) 'Zeile lt Adressentabelle zerlegen und zweites Feld (= Spalte "B") verwenden
Next
Rows(Zeile).EntireRow.ClearContents 'Tabellenzeile löschen
Cells(Zeile, AbSpalte).Resize(1, MaxFeld + 1).Value = Daten 'Datensatz (Teil 1) in Zieltabelle eintragen
Schl = Cells(Zeile, SchlSpalte).Value 'Schlüsselbegriff auslesen
If d.Exists(Schl) Then 'wenn Daten zu diesem Schlüssel vorhanden, ...
Werte = d.Item(Schl) '... diese auslesen und ...
Cells(Zeile, AbSpalte + MaxFeld + 1).Resize(1, UBound(Werte) + 1).Value = Werte 'am Ende der Tabellenzeile hinzufügen
End If
Zeile = Zeile + 1 'nächste Zeile der Zieltabelle
End If
Next
Next
End Sub
- es sich ebenfalls um Textdateien mit dem Trennzeichen ":" handelt
- diese Dateien alle gleich strukturiert sind (Weshalb werden die Daten nicht gleich in einer Datei zusammengefasst?)
- Überschneidungen der Teilenummern (eine Nummer kommt in mehreren Dateien vor) erkannt werden müssen (Was dann zu geschehen hätte, wäre noch zu klären)
Grüße
bastla
[Edit] "Nachschlagen" in den Dateien "Datei1" bis "Datei3" sowie Löschen (alter Daten) der Zieltabelle hinzugefügt [/Edit]
[OT] @bastla
Natürlich kenne ich auch die Situation, dass ich beim Heimkommen einen Zettel auf dem Küchentisch vorfinde mit den Worten:
...und im Kühlschrank liegen dann ein paar Fischfilets, ein halbes Glas Brombeermarmelade, 2 Becher Quark, 4 Stangen Rhabarber und der Rest einer Tube Gleitcreme.
Sollte ich wirklich mit diesen Infos schon anfangen und mache ich damit wirklich allen Beteiligten eine Freude?
Grüße
Biber
[/OT]
Natürlich kenne ich auch die Situation, dass ich beim Heimkommen einen Zettel auf dem Küchentisch vorfinde mit den Worten:
"Zutaten für's Abendessen liegen im Kühlschrank. Fang ruhig schon mal an zu Kochen. Bin zum Essen wieder da."
...und im Kühlschrank liegen dann ein paar Fischfilets, ein halbes Glas Brombeermarmelade, 2 Becher Quark, 4 Stangen Rhabarber und der Rest einer Tube Gleitcreme.
Sollte ich wirklich mit diesen Infos schon anfangen und mache ich damit wirklich allen Beteiligten eine Freude?
Grüße
Biber
[/OT]
[OT] @Biber
Also Dir traue ich durchaus zu, daraus etwas Interessantes zu kreieren - und Du doch auch ...
... und wenn der Rhabarber schon mal da ist ...
Grüße
bastla
[/OT]
Also Dir traue ich durchaus zu, daraus etwas Interessantes zu kreieren - und Du doch auch ...
... und wenn der Rhabarber schon mal da ist ...
Grüße
bastla
[/OT]
[OT ii] @bastla
Ich sach' ma so...
Natürlich gibt es erstmal Pluspunkte, wenn pünktlich etwas Warmes auf dem Tisch steht.
Jedenfalls eigentlich immer.
Aber ich sehe dennoch ein gewisses Restrisiko....
Und überhaupt: zu den drei Dingen, bei denen Zeit nun wirklich keinerlei Rolle spielt, gehört für mich auch das Kochen.
Heisst ja nicht, dass ich deshalb etwas anbrennen lasse.
Grüße
Biber
[/OT ii]
Ich sach' ma so...
Natürlich gibt es erstmal Pluspunkte, wenn pünktlich etwas Warmes auf dem Tisch steht.
Jedenfalls eigentlich immer.
Aber ich sehe dennoch ein gewisses Restrisiko....
Und überhaupt: zu den drei Dingen, bei denen Zeit nun wirklich keinerlei Rolle spielt, gehört für mich auch das Kochen.
Heisst ja nicht, dass ich deshalb etwas anbrennen lasse.
Grüße
Biber
[/OT ii]
Hallo Rio1980!
Die folgende Version holt die "Nachschlage"-Daten aus den Excel-Dateien "Datei1.xls" - "Datei3.xls"
Geschrieben wird, wie auch in der ersten Fassung, in die aktuelle Tabelle der Datei, welche das Makro enthält - und natürlich ist auch das hier produzierte Ergebnis statisch (wird also nur durch neuerliches Ausführen des Makros verändert).
Grüße
bastla
[Edit] Löschen der bereits vorhandenen (alten) Daten des Zieltabellenblattes verbessert [Edit]
Die folgende Version holt die "Nachschlage"-Daten aus den Excel-Dateien "Datei1.xls" - "Datei3.xls"
Sub Importieren()
Basis = "C:\Textdateien"
Typ = "txt" 'Dateityp der zu verarbeitenden Dateien in Kleinbuchstaben
Dateien = Array("C:\Datei1.xls", "C:\Datei2.xls", "C:\Datei3.xls")
Adressen = Array(1, 2, 4, 5, 6, 7, 11) 'da alle Werte in Spalte B stehen, nur die Zeilennummern
SchlSpalte = 2 'Spalte B = Schlüsselspalte für Suche in den Dateien
Delim = ":" 'Trennzeichen
AbZeile = 2 'ab dieser Zeile werden die Werte in die Zieltabelle geschrieben
AbSpalte = 1 'Spalte A; ab dieser Spalte werden die Werte in die Zieltabelle geschrieben
AbZeileQuelle = 1 'erste Datenzeilen in den "Nachschlage"-Dateien
AbSpalteQuelle = 1 'erste Datenspalte in den "Nachschlage"-Dateien
DatenSpaltenQuelle = 7 'Anzahl Datenspalte ohne Schlüsselspalte
MaxFeld = UBound(Adressen) 'höchster Index in der Adressentabelle (= Anzahl der Felder - 1)
Dim Daten()
Set fso = CreateObject("Scripting.FileSystemObject")
Set d = CreateObject("Scripting.Dictionary")
Set Sammel = ThisWorkbook
For Each Datei In Dateien 'alle Dateien in Dictionary einlesen
Set Quelle = Workbooks.Open(Datei)
With Quelle.Worksheets(1)
Zeile = AbZeileQuelle
Schl = Trim(.Cells(Zeile, AbSpalteQuelle).Value)
Do Until Schl = ""
If Not d.Exists(Schl) Then 'noch kein Datensatz mit diesem Schlüssel vorhanden
Werte = .Cells(Zeile, AbSpalteQuelle + 1).Resize(1, DatenSpaltenQuelle) 'Werte (ab 2. Spalte) in Array übernehmen und ...
d.Add Schl, Werte '... im Dictionary zum Schlüssel ablegen
Else 'Schlüssel gab es schon
MsgBox Schl & " ist bereits vorhanden!", vbCritical
End If
Zeile = Zeile + 1
Schl = Trim(.Cells(Zeile, AbSpalteQuelle).Value)
Loop
End With
Quelle.Close
Next
Sammel.Activate
Zeile = AbZeile
Cells(Zeile, AbSpalte).Select 'Startzelle für Daten markieren und ...
Range(Selection, ActiveCell.SpecialCells(xlLastCell)).ClearContents '... ab hier Inhalte löschen
For Each Ordner In fso.GetFolder(Basis).SubFolders 'alle Unterordner des Basisordners durchgehen
For Each Datei In fso.GetFolder(Ordner).Files 'alle Dateien des jeweiligen Unterordners durchgehen ...
If LCase(fso.GetExtensionName(Datei.Name)) = Typ Then '... und nur solche des vorgegebenen Typs verarbeiten
Zeilen = Split(Datei.OpenAsTextStream.ReadAll, vbCrLf) 'alle Zeilen der Datei in Array einlesen
ReDim Daten(MaxFeld)
For i = 0 To MaxFeld 'alle Feldwerte lt Adressentabelle ermitteln
Daten(i) = Split(Zeilen(Adressen(i) - 1), Delim)(1) 'Zeile lt Adressentabelle zerlegen und zweites Feld (= Spalte "B") verwenden
Next
Cells(Zeile, AbSpalte).Resize(1, MaxFeld + 1).Value = Daten 'Datensatz (Teil 1) in Zieltabelle eintragen
Schl = Cells(Zeile, SchlSpalte).Value 'Schlüsselbegriff auslesen
If d.Exists(Schl) Then 'wenn Daten zu diesem Schlüssel vorhanden, ...
Werte = d.Item(Schl) '... diese auslesen und ...
Cells(Zeile, AbSpalte + MaxFeld + 1).Resize(1, DatenSpaltenQuelle).Value = Werte 'am Ende der Tabellenzeile hinzufügen
End If
Zeile = Zeile + 1 'nächste Zeile der Zieltabelle
End If
Next
Next
End Sub
Grüße
bastla
[Edit] Löschen der bereits vorhandenen (alten) Daten des Zieltabellenblattes verbessert [Edit]
Hallo Rio1980!
Sinn der gesamten Aktion: In den Zeilen 25 bis 43 wird aus den Daten der xls-Dateien ein "Dictionary" aufgebaut - dieses besteht aus Datensätzen mit einem Schlüssel (der Teilenummer) und dem zugehörigen Wert (den weiteren Werten aus der Zeile als Array) und existiert nur zur Laufzeit im Arbeitsspeicher. Der Schlüssel muss dabei einmalig sein, daher wird zunächst geprüft, ob er bereits existiert, und wenn ja, die angesprochene Meldung erzeugt.
Zum Testen kannst Du im VBA-Editor den Cursor zwischen "
Eine Anmerkung noch: Da ich nicht weiß, welche Tabellen es in Deinen xls-Dateien gibt, wird jeweils auf die erste dieser Tabellen zugegriffen - siehe dazu Zeile 27. Diese Zeile könntest Du auf
ändern, damit die Tabelle "Blattname" ausgelesen wird.
Grüße
bastla
Allerdings erscheint beim durchführen des Makros ziemlich oft (vermutlich so oft wie Zeilen in meiner generierten Sammeldatei existieren)
Die Meldung betrifft nur das Einlesen der Daten aus "Datei1.xls" - "Datei3.xls" und hat mit den Daten aus den Textdateien nix zu tun ...die Meldung " ist bereits vorhanden!"
Die Meldung sollte auch eine Teilenummer ausgeben ...Sinn der gesamten Aktion: In den Zeilen 25 bis 43 wird aus den Daten der xls-Dateien ein "Dictionary" aufgebaut - dieses besteht aus Datensätzen mit einem Schlüssel (der Teilenummer) und dem zugehörigen Wert (den weiteren Werten aus der Zeile als Array) und existiert nur zur Laufzeit im Arbeitsspeicher. Der Schlüssel muss dabei einmalig sein, daher wird zunächst geprüft, ob er bereits existiert, und wenn ja, die angesprochene Meldung erzeugt.
Zum Testen kannst Du im VBA-Editor den Cursor zwischen "
Sub Importieren()
" und "End Sub
" platzieren und dann mit der Taste F8 in Einzelschritten durch den Ablauf gehen. Dabei kannst Du jederzeit (zB wenn eben die angesprochene Meldung ausgegeben wurde) den Mauszeiger über einer Variablen im Code (zB "Schl
" platzieren und Dir damit deren Wert anzeigen lassen.Eine Anmerkung noch: Da ich nicht weiß, welche Tabellen es in Deinen xls-Dateien gibt, wird jeweils auf die erste dieser Tabellen zugegriffen - siehe dazu Zeile 27. Diese Zeile könntest Du auf
With Quelle.Worksheets("Blattname")
Grüße
bastla
Hallo Rio1980!
Das Redundanz-Problem ist eigentlich auch eine andere Baustelle - die Zeilen 34 und 35 kannst Du also weglassen (es wird dann eben - kommentarlos - immer mit den ersten gefundenen Daten gearbeitet).
Wenn der Tabellenname immer "Tabelle1" lautet, würde ich diesen trotzdem in Zeile 27 verwenden ("Tabelle1" muss nicht immer das erste Blatt der Mappe sein).
Da das Script bei meinen Tests den gewünschten Erfolg gebracht hat, ist es schwer, den Grund für den Fehler mit Deinen Daten nachzuvollziehen - vielleicht noch als Hinweis zur Fehlersuche:
Setze auf die Zeile 61 einen Breakpoint (vor der Zeile in die graue Spalte klicken - es wird dann ein roter Punkt angezeigt) und die Ausführung hält an dieser Stelle an; dann kannst Du, wie oben beschrieben, durch Zeigen (ohne Klicken) mit der Maus auf eine Variable deren Wert anzeigen lassen - insbes die Variable "Schl" aus Zeile 60 wäre hier interessant. Danach kannst Du mit F8 in Einzelschritten weiter gehen, oder mit F5 den Ablauf wieder starten (bis zum nächsten Breakpoint oder bis zum Ende).
Grüße
bastla
Das Redundanz-Problem ist eigentlich auch eine andere Baustelle - die Zeilen 34 und 35 kannst Du also weglassen (es wird dann eben - kommentarlos - immer mit den ersten gefundenen Daten gearbeitet).
Wenn der Tabellenname immer "Tabelle1" lautet, würde ich diesen trotzdem in Zeile 27 verwenden ("Tabelle1" muss nicht immer das erste Blatt der Mappe sein).
Da das Script bei meinen Tests den gewünschten Erfolg gebracht hat, ist es schwer, den Grund für den Fehler mit Deinen Daten nachzuvollziehen - vielleicht noch als Hinweis zur Fehlersuche:
Setze auf die Zeile 61 einen Breakpoint (vor der Zeile in die graue Spalte klicken - es wird dann ein roter Punkt angezeigt) und die Ausführung hält an dieser Stelle an; dann kannst Du, wie oben beschrieben, durch Zeigen (ohne Klicken) mit der Maus auf eine Variable deren Wert anzeigen lassen - insbes die Variable "Schl" aus Zeile 60 wäre hier interessant. Danach kannst Du mit F8 in Einzelschritten weiter gehen, oder mit F5 den Ablauf wieder starten (bis zum nächsten Breakpoint oder bis zum Ende).
Grüße
bastla