2 Spalten einer CSV per Batch in Variable auswerten und an MSSQL-Query übergeben
Hallo,
ich habe eine primitive CSV-Datei, die ich gerne auswerten würde (Spaltentrenner ";").
Die CSV hat beliebig viele Zeilen, muss daher auch zeilenweise verarbeitet werden.
Ich muss nun Spalte 3 und Spalte 5 von insg. 15 Spalten auswerten.
Ich wollte Spalte 3 und Spalte 5 jeweils in eine Variable auslesen.
Im nachfolgenden Schritt sollen die 2 Variablen an ein MSSQL-Query Befehl übergeben werden.
Das MSSQL-Query fragt mit Variable 1 in der Datenbank den Datensatz ab und schreibt dort Variable 2 nieder.
Ich habe hier im Forum dutzende Themen gesehen, gelesen und versucht.
Ich habe zuerst versucht, das CSV überhaupt einmal auszulesen im Batchfile, hatte aber Probleme.
ich habe eine primitive CSV-Datei, die ich gerne auswerten würde (Spaltentrenner ";").
Die CSV hat beliebig viele Zeilen, muss daher auch zeilenweise verarbeitet werden.
Ich muss nun Spalte 3 und Spalte 5 von insg. 15 Spalten auswerten.
Ich wollte Spalte 3 und Spalte 5 jeweils in eine Variable auslesen.
Im nachfolgenden Schritt sollen die 2 Variablen an ein MSSQL-Query Befehl übergeben werden.
Das MSSQL-Query fragt mit Variable 1 in der Datenbank den Datensatz ab und schreibt dort Variable 2 nieder.
Ich habe hier im Forum dutzende Themen gesehen, gelesen und versucht.
Ich habe zuerst versucht, das CSV überhaupt einmal auszulesen im Batchfile, hatte aber Probleme.
@ECHO ON
CLS
COLOR 1e
FOR /F "eol=# tokens=3,5 delims=;" %%1 IN ("test.csv") DO echo %%1 %%2
PAUSE
:setit
set var1=%~1
set var2=%~2
echo %var1% %var2%
PAUSE
Please also mark the comments that contributed to the solution of the article
Content-ID: 250034
Url: https://administrator.de/contentid/250034
Printed on: October 12, 2024 at 18:10 o'clock
25 Comments
Latest comment
Hallo,
Dein Code ist ja schon fast richtig. Du bist nur über den üblichen Fallstrick von Batchscript gestolpert, die verzögerte Variablenerweiterung, hast nicht berücksichtigt, dass die Laufvariablen
Tipp: Mein Tutorial zur FOR-Schleife
Hier mein Vorschlag:
Hierbei gilt es aber zu beachten, dass der Batchscript-Interpreter bestimmte Zeichen als Steuerzeichen/Befehle auswertet. Wenn solche Zeichen in den zu verarbeitenden Zeichenketten enthalten sind, wird es zu Problemen kommen. Auch die Zeichencodierung (Konsole: Codepage 850) kann bei der Weitergabe an ein anderes Programm, das z.B. Windows-1252 erwartet, zu Problemen führen. In solchen Fällen kann man z.B. auf VBScript statt Batchscript ausweichen.
Gruß
Friemler
Dein Code ist ja schon fast richtig. Du bist nur über den üblichen Fallstrick von Batchscript gestolpert, die verzögerte Variablenerweiterung, hast nicht berücksichtigt, dass die Laufvariablen
%%1
und %%2
der FOR
-Schleife nichts mit den Parameter-Variablen %1
und %2
zu tun haben und hast die Syntax von FOR /F
anscheinend noch nicht richtig verstanden (usebackq
fehlt).Tipp: Mein Tutorial zur FOR-Schleife
Hier mein Vorschlag:
@echo off & setlocal
cls
color 1e
for /f "usebackq eol=# tokens=3,5 delims=;" %%a in ("test.csv") do (
call :ProcessItems "%%a" "%%b"
)
exit /b
:ProcessItems
set "Var1=%~1"
set "Var2=%~2"
echo %Var1%
echo %Var2%
exit /b
Hierbei gilt es aber zu beachten, dass der Batchscript-Interpreter bestimmte Zeichen als Steuerzeichen/Befehle auswertet. Wenn solche Zeichen in den zu verarbeitenden Zeichenketten enthalten sind, wird es zu Problemen kommen. Auch die Zeichencodierung (Konsole: Codepage 850) kann bei der Weitergabe an ein anderes Programm, das z.B. Windows-1252 erwartet, zu Problemen führen. In solchen Fällen kann man z.B. auf VBScript statt Batchscript ausweichen.
Gruß
Friemler
Hey,
tja, da haben wir den Salat: Sonderzeichen, die vom Batchscript-Interpreter als Steuerzeichen interpretiert werden und aufeinander folgende Trennzeichen, die nicht als ein Trennzeichen interpretiert werden sollen. Batchscript ist damit einfach überfordert.
Man könnte jetzt auf natives VBScript ausweichen, per VBScript Excel fernsteuern und die Datei damit zerpflücken oder PowerShell benutzen. In letzterem bin ich so gut wie ahnungslos. Um aus den ersten beiden Möglichkeiten die richtige auswählen zu können, musst Du zuerst noch verraten, ob es dabei bleibt, in jeder Zeile der CSV-Datei zwei bestimmte Spalten auszulesen, oder ob da evtl. noch mehr ausgelesen oder gar manipuliert werden muss oder ob es Abhängigkeiten zwischen Spalten gibt (z.B. "verarbeite Spalte X nur dann, wenn Spalte Y den Wert Z enthält" o.ä.). Je komplexer die Aufgabe, um so eher tendiere ich zur Excel-Fernsteuerlösung.
Gruß
Friemler
tja, da haben wir den Salat: Sonderzeichen, die vom Batchscript-Interpreter als Steuerzeichen interpretiert werden und aufeinander folgende Trennzeichen, die nicht als ein Trennzeichen interpretiert werden sollen. Batchscript ist damit einfach überfordert.
Man könnte jetzt auf natives VBScript ausweichen, per VBScript Excel fernsteuern und die Datei damit zerpflücken oder PowerShell benutzen. In letzterem bin ich so gut wie ahnungslos. Um aus den ersten beiden Möglichkeiten die richtige auswählen zu können, musst Du zuerst noch verraten, ob es dabei bleibt, in jeder Zeile der CSV-Datei zwei bestimmte Spalten auszulesen, oder ob da evtl. noch mehr ausgelesen oder gar manipuliert werden muss oder ob es Abhängigkeiten zwischen Spalten gibt (z.B. "verarbeite Spalte X nur dann, wenn Spalte Y den Wert Z enthält" o.ä.). Je komplexer die Aufgabe, um so eher tendiere ich zur Excel-Fernsteuerlösung.
Gruß
Friemler
Hallo chgs2011.
Käse oder nicht, Friemler hat schon Recht. CSV sicher mit Batch zu parsen ist genauso aussichtslos wie XML oder HTML. Und genau mit dem "Leerzellen abfangen" kommst du mit einer einfachen FOR /F Schleife an die Grenzen des Machbaren. Richtig eklig wird es aber (neben den von Friemler schon genannten Problemen), wenn innerhalb eines in Anführungszeichen stehenden Wertes Semikola vorkommen, die nicht als Trennzeichen geparst werden dürfen oder wenn ein einzelnes Line Feed einen Umbruch innerhalb eines Wertes darstellt, während die Kombination aus Carriage Return und Line Feed den Datensatz beendet. Bei solchen Dingen kommt eigentlich tatsächlich nur noch Excel infrage.
Deinem Beispiel zufolge ist der Spaß aber gerade noch mit Batch eine überschaubare Aufgabe.
Grüße
rubberman
Käse oder nicht, Friemler hat schon Recht. CSV sicher mit Batch zu parsen ist genauso aussichtslos wie XML oder HTML. Und genau mit dem "Leerzellen abfangen" kommst du mit einer einfachen FOR /F Schleife an die Grenzen des Machbaren. Richtig eklig wird es aber (neben den von Friemler schon genannten Problemen), wenn innerhalb eines in Anführungszeichen stehenden Wertes Semikola vorkommen, die nicht als Trennzeichen geparst werden dürfen oder wenn ein einzelnes Line Feed einen Umbruch innerhalb eines Wertes darstellt, während die Kombination aus Carriage Return und Line Feed den Datensatz beendet. Bei solchen Dingen kommt eigentlich tatsächlich nur noch Excel infrage.
Deinem Beispiel zufolge ist der Spaß aber gerade noch mit Batch eine überschaubare Aufgabe.
@echo off &setlocal
set "file=test.csv"
set /a "n1 = 2, n2 = 18"
setlocal EnableDelayedExpansion
<"!file!" (
for /f %%i in ('type "!file!"^|find /c /v ""') do for /l %%j in (1 1 %%i) do (
set "line=" &set /p "line="
set /a "c=0"
for %%k in ("!line:;=" "!") do (
set /a "c += 1"
if !c!==!n1! (
endlocal
set "c=%n1%"
set "var1=%%~k"
setlocal EnableDelayedExpansion
)
if !c!==!n2! (
endlocal
set "c=%n2%"
set "var2=%%~k"
setlocal EnableDelayedExpansion
)
)
call :ProcessItems
)
)
endlocal
pause
exit /b
:ProcessItems
echo !var1!
echo !var2!
exit /b
rubberman
Leider habe ich das Problem, dass nur die erste Zeile von zB. 11 übergeben wird
Aha, die erste Zeile von 11. Ist das so etwas wie das 5. Wort von "Bahnhof"?Wo liegt das Problem bei mir?
Kann man nicht ohne reale CSV Datei beantworten. Aber das Hauptproblem ist vermutlich immer noch dass du Batch verwendest...Grüße
rubberman
Ja klar Batch
Naja, noch deutlicher kann man nicht auf die Gefahren hinweisen. Batch mag für einiges taugen, zum Parsen einer CSV Datei aber nun mal nicht.Ich dachte das Script liest je Zeile nur die Spalten vor Steuerzeichen aus
Nein. Jeder Wert wird gelesen, sogar "leere" Werte.Ich kenne den Inhalt deiner CSV nach wie vor nicht.
Die Subroutine :ProcessItems läuft in einer Umgebung mit verzögerter Variablenerweiterung. Also ersetze dort die Prozentzeichen durch Ausrufezeichen bei den Variablen (so wie ich es dir oben vorgeturnt habe). Das verhindert schon mal dass der Batchcode abbricht wenn die Werte Zeichen enthalten, die in Batch eine besondere Bedeutung haben.
Was ich nicht weiß ist ob diese Werte dann Zeichen enthalten, die nicht in einer SQL Anweisung stehen dürfen. Da wäre ich auch sowieso überfragt, da ich davon keine Ahnung habe.
Grüße
rubberman
Hi,
OK, rubberman hat es wieder einmal geschafft, auch dieses Problem mit Batchscript (fast?) zu lösen (dafür meinen Respekt), ich persönlich benutze inzwischen lieber die Programmiersprache, die mir für die Problemstellung am geeignetsten erscheint, d.h. wo ich mir die wenigsten Knoten ins Hirn machen muss um zu einer sicheren Lösung zu kommen
Gruss
Friemler
sooo ein Käse
lass Dir für die Zukunft gesagt sein, dass solches Verhalten von jemandem, der Dir helfen möchte, als unverschämt empfunden werden kann...Also, der Aufbau der CSV-Dateien bleibt IMMER gleich, auch die Spalten die ausgelesen werden müssen.
Es muss NICHTS manipuliert werden, NUR ausgelesen werden um die Ausgaben per SQL an die DB zu übergeben.
Ich habe die Erfahrung gemacht, dass Hilfesuchende oft nicht sofort verraten/erkennen, ob/wie ihre Daten manipuliert werden müssen. Deshalb habe ich Dich gebeten, darüber Auskunft zu geben und nicht behauptet, dass es so ist.Es muss NICHTS manipuliert werden, NUR ausgelesen werden um die Ausgaben per SQL an die DB zu übergeben.
Ich benötige lediglich Spalte X + Y derzeit, habe dies nochmals geprüft. Diese Spalten kommen VOR den Steuerzeichen vor,
so dass unser Script nicht durch alle Spalten laufen / zählen muss.
Ich brauche also den Wert von oben "432784037441" (Spalte 2) und "AB-1409-29303-001" (Spalte 18).
Man müsste also nur die Leerzellen abfangen und mitzählen, da diese einmal befüllt oder leer sind.
Wenn Du wüsstest, wie die benötigten Batchscript-Befehle funktionieren, hättest Du hier keine Hilfe gesucht. Aus diesem Grund hättest Du Dir denken können, dass es schon möglich ist, dass es dabei Probleme gibt, von deren Existenz Du nichts wissen kannst.so dass unser Script nicht durch alle Spalten laufen / zählen muss.
Ich brauche also den Wert von oben "432784037441" (Spalte 2) und "AB-1409-29303-001" (Spalte 18).
Man müsste also nur die Leerzellen abfangen und mitzählen, da diese einmal befüllt oder leer sind.
OK, rubberman hat es wieder einmal geschafft, auch dieses Problem mit Batchscript (fast?) zu lösen (dafür meinen Respekt), ich persönlich benutze inzwischen lieber die Programmiersprache, die mir für die Problemstellung am geeignetsten erscheint, d.h. wo ich mir die wenigsten Knoten ins Hirn machen muss um zu einer sicheren Lösung zu kommen
Gruss
Friemler
Hast du mal versucht einfach 2 Beispielaufrufe für SQLCMD hintereinander zu setzen? Á la
Und (wenn die MSDN Referenz richtig ist) ist es nicht so, dass ein Query eigentlich mit einem Semikolon abgeschlossen wird?
Grüße
rubberman
@echo off &setlocal
"\\hauptserver\Microsoft SQL Server\100\Tools\Binn\SQLCMD.EXE" -S HAUPTSERVER,1083\TEST -d testdb -U admin -P pass -Q "UPDATE tVersand SET cIdentCode = '432784037772' FROM tVersand INNER JOIN tLieferschein ON tVersand.kLieferschein = tLieferschein.kLieferschein WHERE (tVersand.kLieferschein = tVersand.kLieferschein) AND (tLieferschein.cLieferscheinNr = 'AB-1409-29381-001')"
"\\hauptserver\Microsoft SQL Server\100\Tools\Binn\SQLCMD.EXE" -S HAUPTSERVER,1083\TEST -d testdb -U admin -P pass -Q "UPDATE tVersand SET cIdentCode = '432784037788' FROM tVersand INNER JOIN tLieferschein ON tVersand.kLieferschein = tLieferschein.kLieferschein WHERE (tVersand.kLieferschein = tVersand.kLieferschein) AND (tLieferschein.cLieferscheinNr = 'AB-1409-29382-001')"
pause
Grüße
rubberman
Das ist im Trüben fischen.
Dass es ein Delay braucht, kann ich mir nicht vorstellen, kannst du aber testen.
Kannst auch mal ein CALL vor den SQLCMD Aufruf setzen.
Ich glaube aber immer noch nicht dass das des Rätsels Lösung ist. Einfach weiter testen und überflüssigen Kram (insbesondere CLS) aus dem Code schmeißen, damit du auch Fehlermeldungen mitbekommst, falls sie auftreten...
Grüße
rubberman
Dass es ein Delay braucht, kann ich mir nicht vorstellen, kannst du aber testen.
>nul timeout /t 1 /nobreak
Kannst auch mal ein CALL vor den SQLCMD Aufruf setzen.
Ich glaube aber immer noch nicht dass das des Rätsels Lösung ist. Einfach weiter testen und überflüssigen Kram (insbesondere CLS) aus dem Code schmeißen, damit du auch Fehlermeldungen mitbekommst, falls sie auftreten...
Grüße
rubberman
Kann man nicht je Datenzeile 2 neue Variablen vergeben? Sprich dass unser Batch die Variablen fortlaufend hochzählt?
Wenn die Variablenwerte nicht verändert würden, würde die ECHO Ausgabe auch nicht funktionieren. Und ob du nun den Wert in die Console schreibst, oder an ein anderes Programm übergibst, ist völlig egal. Die Expansion der Variablen zum Wert findet im Batchcode statt und nicht erst beim aufgerufenen Programm.
Mit der Schleife hat das auch nichts mehr zu tun, da der Aufruf in einer Subroutine stattfindet.
Es ist doch ziemlich offensichtlich, dass das Problem woanders liegt. Ich muss wohl doch mal parallel Google anwerfen und mich in die SQL Statements einarbeiten...
Grüße
rubberman
schau dir dazu mal "-Q" und "-q" an
Jo, hab ich schon. Wenn ich es richtig verstehe, dann sollte -Q schon OK sein. Das Query wird abgearbeitet und anschließend erfolgt die Abmeldung von der Datenbank.Leider kann ich den ganzen Spaß nicht selbst testen...
Welchen Datentyp hast du cIdentCode und cLieferscheinNr zugeordnet?
Grüße
rubberman
Hmm, mit dem varchar Typ sollte es auch kein Problem geben, soweit ich das beurteilen kann.
Vielleicht mal 'ne andere Richtung einschlagen. Wie müsste denn ein SQL Script beispielhaft aussehen, um alle (oder erst mal nur 2) Queries mit einem Aufruf von SQLCMD abzuarbeiten? Schließlich ist es kein Problem Textdateien per Batch zu erstellen und zu erweitern ...
msdn.microsoft.com/de-de/library/ms170572.aspx
Grüße
rubberman
Vielleicht mal 'ne andere Richtung einschlagen. Wie müsste denn ein SQL Script beispielhaft aussehen, um alle (oder erst mal nur 2) Queries mit einem Aufruf von SQLCMD abzuarbeiten? Schließlich ist es kein Problem Textdateien per Batch zu erstellen und zu erweitern ...
msdn.microsoft.com/de-de/library/ms170572.aspx
Grüße
rubberman
Huch, doch so aufwendig
Ich hatte ursprünglich an etwas in der Art gedacht:
- den Anfang der SQL Datei im Hauptcode erstellen
z.B.
- dann weitere Statements zum erstellen der Daten aus der Subroutine heraus anhängen (unter Verwendung der Variablen VAR1 und VAR2) á la
... wobei ich nicht weiß wie die erste Zeile auszusehen hat ...
- evtl. noch weitere Anweisungen per >> unten anhängen.
- das Script per sqlcmd ausführen.
Auf diese Art hättest du das in einem Rutsch durch.
Grüße
rubberman
Ich hatte ursprünglich an etwas in der Art gedacht:
- den Anfang der SQL Datei im Hauptcode erstellen
z.B.
>"\\Server\Share\Import.sql" (
echo USE eazybusiness
echo GO
echo CREATE TABLE DHL_SENDUNGSDATENIMPORT
echo (TRACKINGID VARCHAR(20^),
echo LIEFERSCHEINNUMMER VARCHAR(20^)^)
echo GO
)
>>"\\Server\Share\Import.sql" echo foo !VAR1! bar !VAR2!;
>>"\\Server\Share\Import.sql" echo GO
- evtl. noch weitere Anweisungen per >> unten anhängen.
- das Script per sqlcmd ausführen.
Auf diese Art hättest du das in einem Rutsch durch.
Grüße
rubberman