it-swarm.com.de

Fügen Sie eine benutzerdefinierte Kopfzeile in die BCP-Ausgabe ein

Kurz gesagt, wir haben hier eine Datenbank, die einige Mitarbeiterdaten wie E-Mail, Vorname, Nachname usw. verwaltet. Unser Unternehmen hat sich in dieses SAP-basierte Spesenabrechnungssystem eingekauft: | Das erfordert einen Export unserer mitarbeiterbasierten Daten in einem sehr seltsamen Format. Ohne auf zu viele Details einzugehen, benötigt der Export dieser Daten insgesamt 137 Spalten, wobei viele dieser Spalten einen leeren Wert haben.

Einfach Ich habe eine Abfrage zusammengestellt, die diese Informationen im Grunde genommen aus unserer Datenbank abgerufen hat, und ich habe einige Konstanten auf das gesetzt, was benötigt wurde. Es ist nicht relevant, was diese Abfrage in dieser Frage ist, es ist einfach eine SELECT Anweisung, die einige Daten abruft.

Ich musste dies dann täglich mit einem bestimmten Dateinamen und einem durch Pipe getrennten Format exportieren, etwas in diesem Sinne:

--employee export
DECLARE @FileName varchar(500)
SET @FileName = (SELECT '\\someFileServer\Public\someFolder\employee_p06010603ace_305_202105_' + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR(19), CONVERT(DATETIME, getdate(), 112), 126), '-', ''), 'T', ''), ':', '') + '.txt')
DECLARE @sql varchar(8000)
DECLARE @header varchar(8000)
SET @sql= 'bcp "exec [MyDBServer].[MyDbName].dbo.ConcurEmployeeExport" queryout ' + @FileName + ' -c -T -t "|"'
Exec master..xp_cmdshell @sql

Perfekt, ich bekomme Zeilen wie diese:

305|Jon| |Doe|10217487|[email protected]| 
305|Steve| |Smith|10217522|[email protected]|

Mit etwa 130 weiteren Spalten wollte ich das alles nicht anzeigen, da es irrelevant ist. Ich dachte, ich wäre fertig, bis der Implementierungskoordinator sagte, dass Ja gut aussieht, außer dass die erste Zeile mit dieser seltsamen Zeile mit einigen Werten beginnen muss.

Das heißt, die resultierende Abfrage, die ich habe, sollte eine zusätzliche Zeile mit einigen Werten enthalten. Einfach, ich dachte, ich würde vereinen, was sie wollten. Und so tat ich es.

Außer der UNION ALL Ich musste einige zusätzliche leere Werte eingeben, um der Anzahl der Spalten in meiner Abfrage zu entsprechen. Das Problem ist, wenn ich den Export ausführe, erhalte ich eine Reihe leerer Spalten, die durch Pipes getrennt sind. Am Ende habe ich Folgendes:

100|0|SSO|UPDATE|EN|N|N| | | | | | | | | | | | | | | | |

Stellen Sie sich das für etwa 120 weitere Spalten vor. Ich habe es ihnen vorgelegt und sie sagten, dass alles gut aussieht, außer Ihrer ersten Reihe. Wir brauchen nur die ersten 7 Werte, das heißt, sie wollen nur Folgendes:

 100|0|SSO|UPDATE|EN|N|N|

Aber ich kann das mit meiner UNION ALL nicht tun, da meine Union alle die gleiche Anzahl von Spalten aus beiden Abfragen erfordert. Also dachte ich, ich könnte nach dem Generieren dieser Datei einfach die | in der ersten Zeile nach dem letzten N von oben ersetzen.

Ist dies möglich, ohne dafür eine andere App/Schnittstelle schreiben zu müssen? Ich möchte behalten, was ich habe, aber nur die erste Zeile so ändern, dass das Ergebnis, das ich erhalte, feststeht. Derzeit ist hier ein Beispiel von drei Zeilen:

100|0|SSO|UPDATE|EN|N|N| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 

305|Jon| |Doe|11111|[email protected]| |[email protected]|en_US|USA| |TK_Symbolic|USD| |Y|USA|IS|0000202105|0120|CC|371000000| | | |030257| | | | | | | | | | | | |030257| | | |USA0000202105|N|N| | |N|N|N|N|N|N|N| | | | | |10217495| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |EOL

305|Steve| |Smith|22222|[email protected]| |[email protected]|en_US|USA| |TK_Symbolic|USD| |Y|USA|IS|0000202105|0120|CC|371000000| | | |030177| | | | | | | | | | | | |030177| | | |USA0000202105|N|N| | |N|N|N|N|N|N|N| | | | | |10217495| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |EOL

Ich muss es dazu bringen:

100|0|SSO|UPDATE|EN|N|N|

305|Jon| |Doe|11111|[email protected]| |[email protected]|en_US|USA| |TK_Symbolic|USD| |Y|USA|IS|0000202105|0120|CC|371000000| | | |030257| | | | | | | | | | | | |030257| | | |USA0000202105|N|N| | |N|N|N|N|N|N|N| | | | | |10217495| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |EOL

305|Steve| |Smith|22222|[email protected]| |[email protected]|en_US|USA| |TK_Symbolic|USD| |Y|USA|IS|0000202105|0120|CC|371000000| | | |030177| | | | | | | | | | | | |030177| | | |USA0000202105|N|N| | |N|N|N|N|N|N|N| | | | | |10217495| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |EOL

Beachten Sie in der ersten Zeile, wie ich alle | entfernt habe. Idealerweise möchte ich dies in der Abfrage tun, die die Datei exportiert. Etwas, um all dies zu entfernen | | in der ersten Zeile nach dem Export?

Die erste Zeile ist statisch und wird generiert mit:

SELECT
    '100' AS [Transaction Type],    --1
    '0' AS [Error Threshold],   --2
    'SSO' AS [Password Generation], --3
    'UPDATE' AS [Existing Record Handling], --4
    'EN' AS [Language Code],    --5
    'N' AS [Validate Expense Group],    --6
    'N' AS [Validate Payment Group],    --7

Leider sagt mir mein Gehirn immer wieder, dass dies keine gute Idee ist/nicht möglich ist. Ich weiß, dass ich dies in .net leicht tun kann, aber ich würde es hassen, wenn noch ein anderes Programm da draußen sitzen würde, das solche Dinge tut.

6
JonH

Sie können ein CMD-Skript erstellen, um eine temporäre Header-Zeilendatei zu erstellen, BCP auszuführen und dann die BCP-Ausgabe an die temporäre Header-Datei anzuhängen. Dies würde über xp_cmdshell Aufgerufen werden, genau wie der bestehende Aufruf von BCP in Ihrem aktuellen Setup.

Hier ist das CMD-Skript, das ich AddHeaderToExportFile.cmd genannt habe. Es werden zwei Parameter benötigt:

  1. Der Dateiname.
  2. Die Kopfzeile. Wenn es sich ändert, müssen Sie nur die gespeicherte Prozedur aktualisieren.

Erstellen Sie einfach eine neue Textdatei im Windows Explorer und ersetzen Sie den Namen (einschließlich der Erweiterung .txt) durch AddHeaderToExportFile.cmd. Bearbeiten Sie dann AddHeaderToExportFile.cmd und fügen Sie den folgenden Code ein und speichern Sie ihn.

AddHeaderToExportFile.cmd :

@ECHO OFF

SET TempHeaderRowFile="%TEMP%\TempHeader.txt"
SET TempOutputFile="%TEMP%\TempOutput.txt"


BCP "EXEC [MyDBServer].[MyDbName].dbo.ConcurEmployeeExport" queryout %TempOutputFile% -c -C 1252 -T -t "|"

ECHO %~2 >  %TempHeaderRowFile%

REM Concatenate Header + BCP_Output -> @FileName
REM /V = Verifies that new files are written correctly.
REM /Y = Suppresses prompting to confirm you want to overwrite an existing destination file
REM /B = treat files as Binary (else you get an extraneous CHAR(26) at the end)
COPY /V /Y /B %TempHeaderRowFile% + %TempOutputFile% %1

REM Delete the temporary Header and BCP output files
IF EXIST %TempHeaderRowFile% DEL /Q %TempHeaderRowFile%
IF EXIST %TempOutputFile% DEL /Q %TempOutputFile%

Wenn Sie Ihr ursprüngliches Skript anpassen, um das neue CMD-Skript aufzurufen, sollte Ihr neues SQL ungefähr so ​​aussehen:

Gespeicherte Prozedur :

--employee export
DECLARE @FileName NVARCHAR(500)
SET @FileName = N'\\someFileServer\Public\someFolder\employee_p06010603ace_305_202105_' +
      REPLACE(REPLACE(REPLACE(
           CONVERT(NVARCHAR(19), CONVERT(DATETIME, GETDATE(), 112), 126),
                              N'-', N''), N'T', N''), N':', N'') +
      N'.txt';

DECLARE @Command NVARCHAR(4000),
        @Header   NVARCHAR(500);

SET @Header = N'100|0|SSO|UPDATE|EN|N|N|';

SET @Command = N'C:\TEMP\BCP\AddHeaderToExportFile.cmd "' +
               @FileName +
               N'", "' +
               REPLACE(@Header, N'|', N'^|') +
               N'"';

EXEC xp_cmdshell @Command; --, NO_OUTPUT;

[~ # ~] oder [~ # ~] können Sie eine Textdatei erstellen, die den Wert der Kopfzeile enthält, und dann das CMD-Skript insgesamt überspringen und verwenden Sie mehrere Aufrufe von xp_cmdshell, um dasselbe zu erreichen:

--employee export
DECLARE @FileName NVARCHAR(500),
        @HeaderFile NVARCHAR(500);
SET @FileName = N'\\someFileServer\Public\someFolder\employee_p06010603ace_305_202105_' +
      REPLACE(REPLACE(REPLACE(
           CONVERT(NVARCHAR(19), CONVERT(DATETIME, GETDATE(), 112), 126),
                              N'-', N''), N'T', N''), N':', N'') +
      N'.txt';
SET @HeaderFile = N'\\someFileServer\public\someFolder\header.txt'; -- static header row

DECLARE @Command NVARCHAR(4000);

SET @Command = N'BCP "EXEC [MyDBServer].[MyDbName].dbo.ConcurEmployeeExport" queryout ' + @FileName + 'tmp -c -C 1252 -T -t "|"';
EXEC xp_cmdshell @Command; --, NO_OUTPUT;

SET @Command = N'COPY /V /Y /B ' + @HeaderFile + N' + ' + @FileName + N'tmp ' + @FileName;
EXEC xp_cmdshell @Command; --, NO_OUTPUT;

SET @Command = N'IF EXIST ' + @FileName + N'tmp DEL /Q ' + @FileName + N'tmp';
EXEC xp_cmdshell @Command; --, NO_OUTPUT;
4
Solomon Rutzky

Eine Option, die Sie in Betracht ziehen könnten, ist die Trennung der beiden. Erstellen Sie eine Datei mit Ihrem Export und allen Feldern. Die andere Datei hat nur Ihren Header. Der letzte Schritt wäre, die beiden mit so etwas zu kombinieren:

REM create the header file
ECHO 100|0|SSO|UPDATE|EN|N|N| >"MyExport.txt.header"
REM append the bcp export to the header file
TYPE "MyExport.txt">>"MyExport.txt.header"
REM rename the header file back to the export file name
MOVE /y "MyExport.txt.header" "MyExport.txt"

Sie haben erwähnt, dass der Export täglich erfolgt. Gibt es dafür einen SQL-Jobplan? Dies kann ein Schritt sein, der dem Job mit dem Typ Betriebssystem (CmdExec) hinzugefügt wird. Es muss kein "externer" Prozess sein, wenn ich Sie richtig verstehe. Der gesamte Code kann in den Jobschritt eingegeben werden.

Wenn Sie nicht damit vertraut sind, können Sie sich auch mit SQLCMD befassen. Fazit: Ich glaube, Sie haben Recht: Was Sie wollen, kann mit bcp wahrscheinlich nicht direkt in einem Schritt erledigt werden.

4
AWEInCA