Text von festen Positionen auslesen und in 2te Datei schreiben
Hallo zusammen,
ich brauche etwas mehr Hilfe um ein kleines Problem zu lösen.
Ich bekomme Textdateien die an bestimmten Positionen die benötigten Infos beinhalten.
Es sind immer feste Positionen und feste Anzahl Zeichen.
Daraus wird ein SQL Script generiert der dann in die Datenbank gepumpt wird.
Bis jetzt werden die Dateien händisch auf ein AutoitScript geschmissen der dann das SQL Script generiert.
SQL Script sieht so aus
INSERT INTO [SchnittstelleLog].[dbo].[Auswertung] ([Aktionszeit], [Versendungsart]) VALUES('20090915144539', 'P');
INSERT INTO [SchnittstelleLog].[dbo].[Auswertung] ([Aktionszeit], [Versendungsart]) VALUES('20090915143523', 'P');
Die Textfiles sehen ungefähr so aus. (am ende Rauten #, aber sonst keine Sonderzeichen, nur ab und zu Leerzeichen)
ASDF000123213213 0025487878987
Benötigte Zeichenketten:
$Aktionszeit = 14, 4
$Versendungsart = 20, 1
$IDP = 42, 8
$IDS = 25, 6
Meine Ansatz sieht so aus...
Muss ich für jede Zeichenkette eigene :ProcessLine erstellen ? ABER wie ?
ich brauche etwas mehr Hilfe um ein kleines Problem zu lösen.
Ich bekomme Textdateien die an bestimmten Positionen die benötigten Infos beinhalten.
Es sind immer feste Positionen und feste Anzahl Zeichen.
Daraus wird ein SQL Script generiert der dann in die Datenbank gepumpt wird.
Bis jetzt werden die Dateien händisch auf ein AutoitScript geschmissen der dann das SQL Script generiert.
SQL Script sieht so aus
INSERT INTO [SchnittstelleLog].[dbo].[Auswertung] ([Aktionszeit], [Versendungsart]) VALUES('20090915144539', 'P');
INSERT INTO [SchnittstelleLog].[dbo].[Auswertung] ([Aktionszeit], [Versendungsart]) VALUES('20090915143523', 'P');
Die Textfiles sehen ungefähr so aus. (am ende Rauten #, aber sonst keine Sonderzeichen, nur ab und zu Leerzeichen)
ASDF000123213213 0025487878987
Benötigte Zeichenketten:
$Aktionszeit = 14, 4
$Versendungsart = 20, 1
$IDP = 42, 8
$IDS = 25, 6
Meine Ansatz sieht so aus...
@echo off & setlocal & enableDelayedExpansion
Datei=C:\Import\*.txt
for /f "usebackq delims=" %%i in ("%Datei%") do call :ProcessLine "%%i"
goto :eof
:ProcessLine
set "Zeile=%~1"
::ab 14 Zeichen 4 Buchstaben ausgeben
(echo %Zeile:~14,4%)>>"script.sql"
goto :eof
Muss ich für jede Zeichenkette eigene :ProcessLine erstellen ? ABER wie ?
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 126045
Url: https://administrator.de/contentid/126045
Ausgedruckt am: 23.11.2024 um 12:11 Uhr
9 Kommentare
Neuester Kommentar
Hallo Andynix!
Die Ausgabezeile musst Du aus den einzelnen Bestandteilen zusammensetzen, also etwa:
Grüße
bastla
Muss ich für jede Zeichenkette eigene :ProcessLine erstellen ?
Mitnichten - das "Line" bezieht sich auf die eingelesene Zeile.Die Ausgabezeile musst Du aus den einzelnen Bestandteilen zusammensetzen, also etwa:
>>"script.sql" echo INSERT INTO [SchnittstelleLog].[dbo].[Auswertung] ([%Zeile:~14,4%], [%Zeile:~20,1%]) VALUES('%Zeile:~42,8%%Zeile:~25,6%','P');
bastla
Moin Andynix und bastla,
noch zweieinhalb Ergänzungen dazu.
Wenn es sich doch um Massendatenverarbeitung handelt, dann ist der Plan, das mit einzelnen INSERT-Statements zu machen, ja schon mal ein Anfang.
Aber es gibt Datenbanken, die brauchen dann zum Einlesen von 10000 dieser Einzel-Inserts ein Stündchen, weil der Treiber leider Gates kein Abschalten des Autocommits zulässt und nach jedem f*cking Kasperstatement erstmal warten angesagt ist.
Ebenso gibt es allerdings auch -je nach Datenbankbleich- mehrere bessere und/oder Umgehungsstrategien.
Da du von SQLServer sprichst und diese "[dbo].[Tabellenname]"-Schreibweise es nahelegt, das du wohl zur täglichen Arbeit mit einen M$-Sqlserver gezwungen wirst:
Wenn Du keine Dump/DataPumpfiles erzeugen willst/sollst, sondern über INSERT-Statements gehen musst:
... lieber STATTDESSEN solche:
Ab SqlServer 2008 geht es etwas normaler (also ohne Workaround):
Dann geht die Erzeugung des SQls etwas flotter, die .sql-Dateien werden handlicher und wartbarer und selbst ein MSSqlServer rennt wie Sau.
Grüße
Biber
noch zweieinhalb Ergänzungen dazu.
Wenn es sich doch um Massendatenverarbeitung handelt, dann ist der Plan, das mit einzelnen INSERT-Statements zu machen, ja schon mal ein Anfang.
Aber es gibt Datenbanken, die brauchen dann zum Einlesen von 10000 dieser Einzel-Inserts ein Stündchen, weil der Treiber leider Gates kein Abschalten des Autocommits zulässt und nach jedem f*cking Kasperstatement erstmal warten angesagt ist.
Ebenso gibt es allerdings auch -je nach Datenbankbleich- mehrere bessere und/oder Umgehungsstrategien.
Da du von SQLServer sprichst und diese "[dbo].[Tabellenname]"-Schreibweise es nahelegt, das du wohl zur täglichen Arbeit mit einen M$-Sqlserver gezwungen wirst:
Wenn Du keine Dump/DataPumpfiles erzeugen willst/sollst, sondern über INSERT-Statements gehen musst:
- Versionen vor SqlServer 2005:
INSERT INTO [SchnittstelleLog].[dbo].[Auswertung] ([Aktionszeit], [Versendungsart])
VALUES('20090915144539', 'P');
INSERT INTO [SchnittstelleLog].[dbo].[Auswertung] ([Aktionszeit], [Versendungsart])
VALUES('20090915144123', 'P');
....
... lieber STATTDESSEN solche:
INSERT INTO [SchnittstelleLog].[dbo].[Auswertung] ([Aktionszeit], [Versendungsart])
SELECT '20090915144539', 'P'
UNION ALL
SELECT '20090915144123', 'P'
UNION ALL
SELECT '20090915144234', 'P'
UNION ALL
SELECT '20090915144456', 'P'
UNION ALL
SELECT '20090915144567', 'X'
UNION ALL
.....
[...und noch 30 weitere UNION ALL...nächste Zeile-mit-Values..]
GO
[...nächste 30 Sätze]...
GO
...
Ab SqlServer 2008 geht es etwas normaler (also ohne Workaround):
INSERT INTO [SchnittstelleLog].[dbo].[Auswertung] ([Aktionszeit], [Versendungsart])
VALUES
('20090915144539', 'P'),
('20090915144123', 'P'),
('20090915144234', 'P'),
('20090915144345', 'P'),
('20090915144567', 'X'),
....
Dann geht die Erzeugung des SQls etwas flotter, die .sql-Dateien werden handlicher und wartbarer und selbst ein MSSqlServer rennt wie Sau.
Grüße
Biber
Hallo Andynix!
Etwa so:
Grüße
bastla
Etwa so:
@echo off & setlocal enableDelayedExpansion
set "Ordner=z:\"
set "filter=*.txt"
:check
pushd "%Ordner%"
for %%d in (dir /b "%filter%") do ( for /f "usebackq delims=" %%i in ("%%d") do call :ProcessLine "%%i")
popd
goto :eof
:ProcessLine
set "Zeile=%~1"
>>"script.sql" echo INSERT INTO [SchnittstelleLog].[dbo].[Auswertung] ([Aktionszeit], [Versendungsart], [Vorgangsnummer], [Aktenzeichen] , [IDST]) VALUES('%Zeile:~103,4%', '%Zeile:~89,1%', '%Zeile:~200,6%/%Zeile:~217,8%/%Zeile:~236,4%', '-', '%Zeile:~24,6%' );
goto :eof
eine Datei zu überspringen, wenn "IDST0000"
"IDST0000" bezieht sich auf den Dateinamen oder den Inhalt? So oder so, Du kannst dafür "findstr /v
" verwenden ...Grüße
bastla
Hallo Andynix!
Sorry, hatte vorher nicht genau genug gelesen ...
Natürlich sind in einer "for /f"-Schleife Hochkommata gefragt - mit dem Filtern zusammen könnte das etwa so aussehen:
Falls nicht unmittelbar nach dem String "IDST0000", sondern nach "0000" an der entsprechenden Zeilenposition gefiltert werden soll, musst Du das eben im Unterprogramm ":ProcessLine" erledigen ...
Grüße
bastla
P.S.:
[Edit] Überzählige Klammer am Ende der "for"-Zeile entfernt [/Edit]
Sorry, hatte vorher nicht genau genug gelesen ...
Natürlich sind in einer "for /f"-Schleife Hochkommata gefragt - mit dem Filtern zusammen könnte das etwa so aussehen:
@echo off & setlocal enableDelayedExpansion
set "Ordner=z:\"
set "filter=*.txt"
:check
pushd "%Ordner%"
for /f %%d in ('dir /b "%filter%'") do for /f "delims=" %%i in ('findstr /v "IDST0000" "%%d"') do call :ProcessLine "%%i"
popd
goto :eof
:ProcessLine
set "Zeile=%~1"
>>"script.sql" echo INSERT INTO [SchnittstelleLog].[dbo].[Auswertung] ([Aktionszeit], [Versendungsart], [Vorgangsnummer], [Aktenzeichen] , [IDST]) VALUES('%Zeile:~103,4%', '%Zeile:~89,1%', '%Zeile:~200,6%/%Zeile:~217,8%/%Zeile:~236,4%', '-', '%Zeile:~24,6%' );
goto :eof
Grüße
bastla
P.S.:
Ich muss die "Batch for Runaways" genauer durch studieren.
Gegen diesen Vorsatz ist nun wirklich nix einzuwenden ... [Edit] Überzählige Klammer am Ende der "for"-Zeile entfernt [/Edit]
Hallo Andynix!
Wenn Du übrigens anstelle von "echo off" ein "echo on" verwendest, kannst Du genau nachvollziehen, was jeweils an Befehlen ausgeführt wird (bei der Gelegenheit ließe sich dann auch gleich das unnötige "
[Edit]
Wie's aussieht ist heute ist nicht so ganz mein Tag - Du hattest ja "Datei überspringen" geschrieben, und dann müsste die Zeile eher so aussehen:
[/Edit]
Grüße
bastla
die Textdateien haben Leerzeichen in Namen! - deswegen greift sich FINDSTR nur den ersten Teil des Namens
Kann eigentlich nicht sein, da "%%d
" ja unter Anführungszeichen steht - eher schon, weil ein "delims=
" fehlt - das wäre jetzt der Moment, für die Dateiauswahl ganz auf "for /f
" zu verzichten (dann könnten auch "pushd
" und "popd
" entfallen) und das so zu formulieren:for %%d in ("%ordner%%filter%") do for /f "delims=" %%i in ('findstr /v "IDST0000" "%%d"') do call :ProcessLine "%%i"
setlocal enableDelayedExpansion
" eliminieren).[Edit]
Wie's aussieht ist heute ist nicht so ganz mein Tag - Du hattest ja "Datei überspringen" geschrieben, und dann müsste die Zeile eher so aussehen:
for %%d in ("%ordner%%filter%") do findstr "IDST0000" "%%d">nul || for /f "usebackq delims=" %%i in ("%%d") do call :ProcessLine "%%i"
Grüße
bastla