Zwei CSV Dateien verknüpfen
Hallo zusammen,
ich habe das Problem das ich Informationen, sprich Spalten, aus zwei CSV Dateien miteinander verknüpfen möchte.
Zum Beispiel habe ich eine CSV mit den Namen (
ID,Name
1,Huber
2,Meier
3,Schmid
4,Mueller
) und eine zweite mit dem dazugehörigem Ort (
ID,Ortsname
3,Berlin
1,Hamburg
4,Stuttgart
2,Muenchen
). Nun möchte ich anhand der „Spalte“ „ID“ automatisiert folgende Ausgabe zustande bringen:
ID,Name,Ortsname
1,Huber,Hamburg
2,Meier,Muenchen
3,Schmid,Berlin
4,Mueller,Stuttgart
Ich habe es bereits mit der PowerShell, VBSkript und mit dem MS Log Parser versucht, bin jedoch nicht zu einem passenden Ergebnis gekommen.
Das Ergebnis sollte dann wiederrum eine CSV Datei sein.
Schon mal vorab vielen Dank für eure Hilfe...
ich habe das Problem das ich Informationen, sprich Spalten, aus zwei CSV Dateien miteinander verknüpfen möchte.
Zum Beispiel habe ich eine CSV mit den Namen (
ID,Name
1,Huber
2,Meier
3,Schmid
4,Mueller
) und eine zweite mit dem dazugehörigem Ort (
ID,Ortsname
3,Berlin
1,Hamburg
4,Stuttgart
2,Muenchen
). Nun möchte ich anhand der „Spalte“ „ID“ automatisiert folgende Ausgabe zustande bringen:
ID,Name,Ortsname
1,Huber,Hamburg
2,Meier,Muenchen
3,Schmid,Berlin
4,Mueller,Stuttgart
Ich habe es bereits mit der PowerShell, VBSkript und mit dem MS Log Parser versucht, bin jedoch nicht zu einem passenden Ergebnis gekommen.
Das Ergebnis sollte dann wiederrum eine CSV Datei sein.
Schon mal vorab vielen Dank für eure Hilfe...
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Kommentar vom Moderator Biber am 27.04.2010 um 14:13:48 Uhr
Hier stehen bis heute, 27.4..2010 schon so viele kompetente Antworten...
Deshalb setze ich den Beitrag jetzt auf "Beantwortet", egal ob sich Klinger85 jemals wieder meldet oder nicht.
Deshalb setze ich den Beitrag jetzt auf "Beantwortet", egal ob sich Klinger85 jemals wieder meldet oder nicht.
Content-ID: 141054
Url: https://administrator.de/contentid/141054
Ausgedruckt am: 17.11.2024 um 15:11 Uhr
15 Kommentare
Neuester Kommentar
Zitat von @Klinger85:
Ich habe es bereits mit der PowerShell, VBSkript und mit dem MS Log Parser versucht, bin jedoch nicht zu einem passenden Ergebnis
gekommen.
Ich habe es bereits mit der PowerShell, VBSkript und mit dem MS Log Parser versucht, bin jedoch nicht zu einem passenden Ergebnis
gekommen.
Dann zeig doch mal deine Versuche, es wird sich schon jemand finden der den Finger an die richtige(falsche) Stelle legt
Gruß
LotPings
Hallo Klinger85 und willkommen im Forum, hallo LotPings!
Um das etwas abzukürzen : Ich bin in meinem Editor auf folgenden Batch gestoßen:
Grüße
bastla
Um das etwas abzukürzen : Ich bin in meinem Editor auf folgenden Batch gestoßen:
@echo off & setlocal
set "Namen=D:\Namen.txt"
set "Orte=D:\Ortsnamen.txt"
set "Gesamt=D:\Gesamt.txt"
>"%Gesamt%" echo ID,Name,Ortsname
for /f "usebackq skip=1 tokens=1,2 delims=," %%i in ("%Namen%") do for /f "tokens=2 delims=," %%a in ('findstr /b /c:"%%i," "%Orte%"') do >>"%Gesamt%" echo %%i,%%j,%%a
bastla
Hallo bastla,
ja, die Aufgabenstellung kam mir schon bekannt vor
@Klinger85,
ich hab mir das PowerShell Script mal angesehen, läuft bei mir nicht wegen PosH 2.1
Mein Win7-64 hat nur PoSh 2.0. Wenn ich das ignoriere sieht bei mir das Ergebnis genauso aus.
Das ist aber zu komplex um es mal eben zu untersuchen, vielleicht später einmal.
Gruß
LotPings
ja, die Aufgabenstellung kam mir schon bekannt vor
@Klinger85,
ich hab mir das PowerShell Script mal angesehen, läuft bei mir nicht wegen PosH 2.1
Mein Win7-64 hat nur PoSh 2.0. Wenn ich das ignoriere sieht bei mir das Ergebnis genauso aus.
Das ist aber zu komplex um es mal eben zu untersuchen, vielleicht später einmal.
Gruß
LotPings
@77559
[Edit] Trennzeichen in Variable verfrachtet [/Edit]
Grüße
bastla
ja, die Aufgabenstellung kam mir schon bekannt vor
Na gut, dann eben mal etwas Abwechslung :Namen = "D:\Namen.txt"
Orte = "D:\Ortsnamen.txt"
Gesamt = "D:\Gesamt.txt"
Delim = "," 'Trennzeichen
Set fso = CreateObject("Scripting.FileSystemObject")
Set d = CreateObject("Scripting.Dictionary") 'Dictionary für die Orte erstellen
O = Split(fso.OpenTextFile(Orte).ReadAll, vbCrLf) 'gesamte Orte-Datei in Zeilen-Array einlesen ...
For i = 0 To UBound(O) '... und alle Zeilen durchgehen
Felder = Split(O(i), Delim) 'Satz anhand des Trennzeichens aufteilen
If Not d.Exists(Felder(0)) Then 'Feld 0 enthält den Schlüssel - noch nicht vorhanden?
d.Add Felder(0), Felder(1) '... dann hinzufügen (mit Wert aus Feld 1)
Else 'ansonsten Fehlermeldung und Abbruch
WScript.Echo "Fehler in """ & Orte & """ / Zeile " & i + 1 & ": Nummer """ & Felder(0) & """ bereits für """ & d.Item(Felder(0)) & """ vorhanden!"
WScript.Quit
End If
Next
N = Split(fso.OpenTextFile(Namen).ReadAll, vbCrLf) 'gesamte Namen-Datei in Zeilen-Array einlesen ...
For i = 0 To UBound(N) '... und alle Zeilen durchgehen
Felder = Split(N(i), Delim) ''Satz anhand des Trennzeichens aufteilen
If d.Exists(Felder(0)) Then 'Ort mit dem Schlüssel aus Feld 0 vorhanden?
G = G & vbCrLf & N(i) & Delim & d.Item(Felder(0))' ... dann dem Ergebnisstring eine Zeilenschaltung sowie den Namens-Satz und den Ort hinzufügen
Else 'ansonsten Fehlermeldung und Abbruch
WScript.Echo "Fehler in """ & Namen & """ / Zeile " & i + 1 & ": Kein Ort für Nummer """ & Felder(0) & """ gefunden!"
WScript.Quit
End If
Next
fso.CreateTextFile(Gesamt).Write Mid(G, 3) 'Ergebnisstring ab 3. Position (die ersten beiden Stellen enthalten eine unnötige Zeilenschaltung) in Gesamt-Datei schreiben
WScript.Echo "Fertig."
Grüße
bastla
Hallo Klinger85!
Ich war eigentlich nicht davon ausgegangen, dass es Leerzeilen (oder zumindest Zeilen ohne ein Komma) in der Ortsnamen-Datei gibt ...
... aber dagegen sollte sich ja noch was machen lassen:
[Edit] Bezeichnung des "Orte"-Arrays "O" auf Schreibweise mit Kleinbuchstaben "o" geändert, um Verwechslung mit der Ziffer 0 vorzubeugen [/Edit]
Grüße
bastla
Ich war eigentlich nicht davon ausgegangen, dass es Leerzeilen (oder zumindest Zeilen ohne ein Komma) in der Ortsnamen-Datei gibt ...
... aber dagegen sollte sich ja noch was machen lassen:
Namen = "D:\Namen.txt"
Orte = "D:\Ortsnamen.txt"
Gesamt = "D:\Gesamt.txt"
Delim = "," 'Trennzeichen
Set fso = CreateObject("Scripting.FileSystemObject")
Set d = CreateObject("Scripting.Dictionary") 'Dictionary für die Orte erstellen
o = Split(fso.OpenTextFile(Orte).ReadAll, vbCrLf) 'gesamte Orte-Datei in Zeilen-Array einlesen ...
For i = 0 To UBound(o) '... und alle Zeilen durchgehen
Felder = Split(o(i), Delim) 'Satz anhand des Trennzeichens aufteilen
If UBound(Felder) > 0 Then 'nur, wenn der Satz mindestens 2 Felder enthält, verarbeiten ...
If Not d.Exists(Felder(0)) Then 'Feld 0 enthält den Schlüssel - noch nicht vorhanden?
d.Add Felder(0), Felder(1) '... dann hinzufügen (mit Wert aus Feld 1)
Else '... ansonsten Fehlermeldung und Abbruch
WScript.Echo "Fehler in """ & Orte & """ / Zeile " & i + 1 & ": Nummer """ & Felder(0) & """ bereits für """ & d.Item(Felder(0)) & """ vorhanden!"
WScript.Quit
End If
Else
WScript.Echo "Fehler in """ & Orte & """ / Zeile " & i + 1 & ": Unvollständiger Datensatz!"
WScript.Quit
End If
Next
N = Split(fso.OpenTextFile(Namen).ReadAll, vbCrLf) 'gesamte Namen-Datei in Zeilen-Array einlesen ...
For i = 0 To UBound(N) '... und alle Zeilen durchgehen
Felder = Split(N(i), Delim) 'Satz anhand des Trennzeichens aufteilen
If UBound(Felder) > 0 Then 'nur, wenn der Satz mindestens 2 Felder enthält, verarbeiten ...
If d.Exists(Felder(0)) Then 'Ort mit dem Schlüssel aus Feld 0 vorhanden?
G = G & vbCrLf & N(i) & Delim & d.Item(Felder(0))' ... dann dem Ergebnisstring eine Zeilenschaltung sowie den Namens-Satz und den Ort hinzufügen
Else '... ansonsten Fehlermeldung und Abbruch
WScript.Echo "Fehler in """ & Namen & """ / Zeile " & i + 1 & ": Kein Ort für Nummer """ & Felder(0) & """ gefunden!"
WScript.Quit
End If
Else
WScript.Echo "Fehler in """ & Orte & """ / Zeile " & i + 1 & ": Unvollständiger Datensatz!"
WScript.Quit
End If
Next
fso.CreateTextFile(Gesamt).Write Mid(G, 3) 'Ergebnisstring ab 3. Position (die ersten beiden Stellen enthalten eine unnötige Zeilenschaltung) in Gesamt-Datei schreiben
WScript.Echo "Fertig."
Grüße
bastla
Moin bastla,
ich habe deine Korrektur gedanklich und schnipselig nachvollzogen.
Ich würde bei einem Einsatz in einem realitätsnäheren Umfeld (=mehr als 5 Zeilen in jeder der Dateien) allerdings eine kleine nervensparende Anpassung nahelegen.
Bei einer Leerzeile (oder kommalosen Zeile) in einer der CSV-Dateien grätscht das Programm professionell und elegant ab mit
Blöd nur, wenn dann jemand die Leerzeile in Zeile 6 wegeditiert und wieder startet.
Dann nämlich
--> Man/frau muss jede Mistzeile einzeln "reparieren", den Schnipsel neu starten und schauen, wie weit er jetzt kommt.
--> deshalb würde ich die Zeilen 21 und 33 ("Wscript.Quit") auskommentieren, alle bisher auch geschriebenen Fehlersätze genauso anmeckern wie bisher und WEITERMACHEN.
Dann habe ich ZWEI Vorteile.
a) eine erzeugte Gesamt.txt mit allen "funktionierenden" Namen x Ort-Zeilen
b) eine unveränderte, nicht manipulierte Nur-Gelesen-CSV-Datei, die ich mitsamt dem Fehlerprotokoll zurück an den Datenlieferanten schicken kann.
Grüße
Biber
ich habe deine Korrektur gedanklich und schnipselig nachvollzogen.
Ich würde bei einem Einsatz in einem realitätsnäheren Umfeld (=mehr als 5 Zeilen in jeder der Dateien) allerdings eine kleine nervensparende Anpassung nahelegen.
Bei einer Leerzeile (oder kommalosen Zeile) in einer der CSV-Dateien grätscht das Programm professionell und elegant ab mit
>e:\schnipsel\bastlaCsvJoin.vbs
Fehler in "D:\temp\Orte.csv" / Zeile 6: Unvollständiger Datensatz!
Blöd nur, wenn dann jemand die Leerzeile in Zeile 6 wegeditiert und wieder startet.
Dann nämlich
>e:\schnipsel\bastlaCsvJoin.vbs
Fehler in "D:\temp\Orte.csv" / Zeile 6: Unvollständiger Datensatz!
{User editiert, zählt bis drei und startet durch..}
>e:\schnipsel\bastlaCsvJoin.vbs
Fehler in "D:\temp\Orte.csv" / Zeile 445: Unvollständiger Datensatz!
{User editiert, zählt bis dreimaldrei und startet durch..}
>e:\schnipsel\bastlaCsvJoin.vbs
Fehler in "D:\temp\Orte.csv" / Zeile 20045: Unvollständiger Datensatz!
{User editiert, zählt bis dreiundzwanzig und startet durch..}
...
--> Man/frau muss jede Mistzeile einzeln "reparieren", den Schnipsel neu starten und schauen, wie weit er jetzt kommt.
--> deshalb würde ich die Zeilen 21 und 33 ("Wscript.Quit") auskommentieren, alle bisher auch geschriebenen Fehlersätze genauso anmeckern wie bisher und WEITERMACHEN.
Dann habe ich ZWEI Vorteile.
a) eine erzeugte Gesamt.txt mit allen "funktionierenden" Namen x Ort-Zeilen
b) eine unveränderte, nicht manipulierte Nur-Gelesen-CSV-Datei, die ich mitsamt dem Fehlerprotokoll zurück an den Datenlieferanten schicken kann.
Grüße
Biber
@Biber
Du hast natürlich recht, und es ist keine Frage, dass im Ernstfall die Fehlermeldungen in einer Datei landen würden und es auch nicht zum Abbruch käme ...
Da als Batch eigentlich fast ein Einzeiler genügt, sollte die (von vorneherein umfangreichere) VBS-Variante zumindest andeutungsweise einen Mehrwert bekommen, daher habe ich noch die Kontrollen (eigentlich eher zu Demozwecken) mit eingebaut.
Abgesehen davon wäre ja mit der Ursachenforschung / -behebung ohnehin, wie Du schon angemerkt hast, bei der Entstehung der "csv"-Datei anzusetzen ...
Grüße
bastla
Du hast natürlich recht, und es ist keine Frage, dass im Ernstfall die Fehlermeldungen in einer Datei landen würden und es auch nicht zum Abbruch käme ...
Da als Batch eigentlich fast ein Einzeiler genügt, sollte die (von vorneherein umfangreichere) VBS-Variante zumindest andeutungsweise einen Mehrwert bekommen, daher habe ich noch die Kontrollen (eigentlich eher zu Demozwecken) mit eingebaut.
Abgesehen davon wäre ja mit der Ursachenforschung / -behebung ohnehin, wie Du schon angemerkt hast, bei der Entstehung der "csv"-Datei anzusetzen ...
Grüße
bastla
Hallo,
kurz und knapp würde ich es in PS so machen
grüße
Torsten
kurz und knapp würde ich es in PS so machen
$user1 = import-csv users1.csv
$user2 = import-csv users2.csv
$header = "ID,Name,Ortsname"
Add-Content -Value $header Ausgabe.csv
foreach ($ID1 in $user1)
{ foreach ($ID2 in $user2)
{ IF ($ID1.ID -eq $ID2.ID)
{ Add-Content -Value ($ID1.ID.ToString() + "," + $ID1.Name.ToString() + "," + $ID2.Ortsname.ToString()) Ausgabe.csv
}
}
}
grüße
Torsten
...wäre natürlich schön, wenn der Fragesteller Klinger85 noch vor dem wohlverdienten Wochenende antwortet:
Dann könnten wir diesen Beitrag endlich schließen.
Grüße
Biber
"Vielen Dank für die ganzen Batch-, VBS- und Powershell-Lösungen.
Aus Zeitmangel konnte ich nicht alles austesten und habe das Problem inzwischen mit dem NotePad gelöst."
Aus Zeitmangel konnte ich nicht alles austesten und habe das Problem inzwischen mit dem NotePad gelöst."
Dann könnten wir diesen Beitrag endlich schließen.
Grüße
Biber
Auch allen ein schönes WE,
@Torsten, auch bei PoSh führen viele Wege nach Rom, die geschachtelten Schleifen sind ein in diesem kurzen Beispiel tolerierbares "brute force".
Effizienter wäre ein HashArrayTable:
Gruß
Lotpings
@Torsten, auch bei PoSh führen viele Wege nach Rom, die geschachtelten Schleifen sind ein in diesem kurzen Beispiel tolerierbares "brute force".
Effizienter wäre ein Hash
$namen = import-csv .\namen.csv
$orte = @{}
Import-Csv .\orte.csv | %{$orte.item($_.ID.ToString()) = $_.Ortsname.ToString()}
$header = "ID,Name,Ortsname"
Add-Content -Value $header Ausgabe.csv
foreach ($name in $namen)
{ Add-Content -Value ($name.ID.ToString() + "," + $name.Name.ToString() + "," + $orte[$name.ID].ToString()) Ausgabe.csv}
Gruß
Lotpings
Hallo LotPings,
danke für das Script (ja es läuft um einiges schneller), ganze Script war auch nur ein Gedankenspiel. Habe das Script so aufgebaut wie ich es mit ausgedruckten Listen machen würde.
Mit HashTables (nicht arrays! ) habe ich noch so meine Verständnissprobleme. Eine Bitte hätte ich noch, wenn man Scripte postet, liest sich ein ForEach-Object besser als ein %. Ja ich kann es lesen, aber andere fragen sich evtl. was das sein soll.
Grüße Torsten.
danke für das Script (ja es läuft um einiges schneller), ganze Script war auch nur ein Gedankenspiel. Habe das Script so aufgebaut wie ich es mit ausgedruckten Listen machen würde.
Mit HashTables (nicht arrays! ) habe ich noch so meine Verständnissprobleme. Eine Bitte hätte ich noch, wenn man Scripte postet, liest sich ein ForEach-Object besser als ein %. Ja ich kann es lesen, aber andere fragen sich evtl. was das sein soll.
Grüße Torsten.
Zitat von @5t8d1e:
Eine Bitte hätte ich noch, wenn man Scripte postet, liest sich ein ForEach-Object besser als ein %.
Ja ich kann es lesen, aber andere fragen sich evtl. was das sein soll.
Hallo Torsten,Eine Bitte hätte ich noch, wenn man Scripte postet, liest sich ein ForEach-Object besser als ein %.
Ja ich kann es lesen, aber andere fragen sich evtl. was das sein soll.
strenggenommen ist auch foreach nur ein Alias für foreach-object, auch wenn sich der Sinn eher erschließt
alias | where {$_.Definition -eq "foreach-object"} | ft --auto
CommandType Name Definition
----------- ---- ----------
Alias % ForEach-Object
Alias foreach ForEach-Object
Ansonsten gehört es IMHO zu Lernkurve valide Syntax Elemente zu verstehen
Gruß
LotPings
PS: Zur Klärung ggfs weiterer auftretender Fragen einfach dies eingeben
"%", "where", "ft" | %{alias $_}
oder gleich dies:
"%", "where", "ft" | %{alias $_} | %{get-help $_.Definition} | more