web-dev-qa-db-fra.com

Insérer une ligne d'en-tête personnalisée dans la sortie BCP

Histoire longue courte Nous avons une base de données ici qui gère des données d'employés tels que le courrier électronique, le prénom, le nom de famille, etc. Notre société a acheté dans ce système de rapport de dépenses basé sur SAP: | Cela nécessite une exportation de données sur nos employés dans un format très étrange. Sans entrer dans trop de détails, l'exportation de ces données nécessite un total de 137 colonnes, plusieurs de ces colonnes ayant une valeur vide.

Simple Je mets ensemble une requête qui a essentiellement tiré ces informations de notre base de données et j'ai défini certaines constantes à ce qui était nécessaire. Ce n'est pas pertinent que cette requête est dans cette question, sa simple déclaration SELECT tire certaines données.

Je devais ensuite exporter cela quotidiennement avec un nom de fichier spécifique et avec un format délimité de tuyau, quelque chose à cet effet:

--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

Parfait, je reçois des lignes comme ceci:

305|Jon| |Doe|10217487|10217487@t| 
305|Steve| |Smith|10217522|10217522@t|

Avec environ 130 colonnes de plus, je ne voulais pas afficher tout cela puisqu'il n'est pas pertinent. Je pensais que j'avais fini jusqu'à ce que le coordinateur de la mise en œuvre ait dit oui, sauf que la première ligne doit commencer avec cette étrange rangée avec certaines valeurs.

Signification La requête résultante que j'ai dû avoir une ligne supplémentaire avec des valeurs de certaines valeurs..simples, je pensais inscrire l'union de ce qu'ils voulaient.. et je l'ai fait.

Sauf le UNION ALL Je devais mettre dans certaines valeurs vides supplémentaires pour correspondre au nombre de colonnes dans ma requête. Le problème est que lorsque j'exécute l'exportation, je me retrouve avec une bande de colonnes vides délimitées, je me retrouve avec ceci:

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

Imaginez que cela se passe environ 120 colonnes supplémentaires. Je leur ai soumis ceci et ils ont bien dit que tout va bien, sauf votre première rangée. Nous avons juste besoin des 7 premières valeurs, c'est-à-dire qu'elles veulent seulement ceci:

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

Mais je ne peux pas faire cela avec mon syndicat tout, car mon syndicat nécessite tous le même nombre de colonnes des deux requêtes. Donc, je pensais que je pouvais en quelque sorte après avoir généré ce fichier, remplacez-vous le | 'S dans la première ligne après le dernier N d'en haut.

Est-ce possible sans avoir à écrire une autre application/interface pour faire cela? Je veux garder ce que j'ai mais modifier seulement cette première ligne de sorte que le résultat que je reçois est corrigé, il s'agit actuellement d'un échantillon de trois rangées:

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

305|Jon| |Doe|11111|11111@t| |[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|22222@t| |[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

J'ai besoin de l'obtenir à ceci:

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

305|Jon| |Doe|11111|11111@t| |[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|22222@t| |[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

Notez la première ligne Comment j'ai supprimé toutes ces personnes | Idéalement, je voudrais faire cela dans peut-être la requête qui exporte le fichier. Quelque chose à l'effet de supprimer tout cela | | | sur la première ligne après l'exportation?

La première ligne est statique, générée en utilisant:

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

Malheureusement, mon cerveau continue à me dire que ce n'est pas une bonne idée/n'est pas possible. Je sais que je peux facilement faire cela à .Net, mais je détesterais avoir encore un autre programme assis là-bas faisant ces sortes de choses.

6
JonH

Vous pouvez créer un script cmd pour créer un fichier de lignes d'en-tête Temp, exécuter BCP, puis appendez la sortie BCP dans le fichier d'en-tête Temp. Ceci serait appelé via xp_cmdshell, comme l'appel existant à BCP Dans votre configuration actuelle.

Voici le script CMD, que j'ai nommé addheadertoexportfile.cmd. Il faut deux paramètres:

  1. Le nom de fichier.
  2. La rangée d'en-tête. Si cela change, il vous suffit de mettre à jour la procédure stockée.

Créez simplement un nouveau fichier texte dans l'Explorateur Windows, puis remplacez le nom (y compris l'extension .txt) avec Addheadertoexportfile.cmd. Puis modifier Addheadertoexportfile.cmd et coller dans le code suivant et enregistrez-la.

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%

Adapter votre script d'origine pour appeler le nouveau script CMD, votre nouveau SQL devrait être quelque chose comme:

Procédure stockée :

--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;

[~ # ~] ou [~ # ~] , vous pouvez créer un fichier texte pour maintenir la valeur de la ligne d'en-tête, puis ignorer le script cmd et utilisez plusieurs appels vers xp_cmdshell Pour accomplir la même chose:

--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

Une option que vous pourriez envisager est de séparer les deux. Créez un fichier avec votre exportation et tous les champs. L'autre fichier a juste votre en-tête. La dernière étape consisterait à combiner les deux avec quelque chose comme ceci:

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"

Vous avez mentionné que l'exportation a été effectuée quotidiennement. Existe-t-il un programme de travail SQL pour faire cela? Cela pourrait être une étape ajoutée au travail à l'aide du type Système d'exploitation (CMDEXEC) Type. Il ne doit pas nécessairement être un processus "externe" si je vous comprends correctement. Tout le code peut être entré dans l'étape du travail.

Si vous ne le connaissez pas, l'autre chose que vous pouvez examiner est SQLCMD. En bout de ligne, c'est que vous croyez que vous êtes correct: ce que vous voulez probablement ne peut probablement pas être fait avec BCP directement en une étape.

4
AWEInCA