在 BCP 输出中插入自定义标题行

Jon*_*onH 6 sql-server-2005 sql-server bcp format

长话短说,我们这里有一个数据库,用于管理一些员工数据,例如电子邮件、名字、姓氏等。我们公司购买了这个基于 SAP 的费用报告系统:| 这需要以非常奇怪的格式导出基于员工的数据。在不涉及太多细节的情况下,此数据的导出总共需要 137 列,其中许多列具有空值。

简单 我整理了一个查询,该查询基本上从我们的数据库中提取了这些信息,并设置了一些需要的常量。这个查询在这个问题中是什么并不相关,它只是一个SELECT提取一些数据的语句。

然后,我需要每天使用特定的文件名和管道分隔格式将其导出,效果如下:

--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
Run Code Online (Sandbox Code Playgroud)

完美,我得到这样的行:

305|Jon| |Doe|10217487|10217487@t| 
305|Steve| |Smith|10217522|10217522@t|
Run Code Online (Sandbox Code Playgroud)

大约有 130 多列,不想显示所有这些,因为它无关紧要。我以为我已经完成了,直到实现协调员说 yes 看起来不错,但第一行需要从这个奇怪的行开始并带有一些值。

这意味着我拥有的结果查询应该有一个额外的行,其中包含一些值......简单我以为我会联合他们想要的......所以我做到了。

除了UNION ALL我必须输入一些额外的空值来匹配我的查询中的列数。问题是当我运行导出时,我最终得到了一堆用管道分隔的空列,我最终得到了这个:

100|0|SSO|UPDATE|EN|N|N| | | | | | | | | | | | | | | | |
Run Code Online (Sandbox Code Playgroud)

想象一下,还有大约 120 列。我把这个提交给他们,他们说除了你的第一排外,一切看起来都很好。我们只需要前 7 个值,也就是说他们只需要这个:

 100|0|SSO|UPDATE|EN|N|N|
Run Code Online (Sandbox Code Playgroud)

但是我不能用我的 UNION ALL 来做到这一点,因为我的 union all 需要来自两个查询的相同数量的列。所以我想我可以在生成这个文件后以某种方式替换N上面最后一行之后的第一行中的 | 。

这是否可能而无需编写另一个应用程序/界面来执行此操作?我想保留我所拥有的,但只修改第一行,以便我得到的结果是固定的,目前这里是三行的示例:

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

305|Jon| |Doe|11111|11111@t| |jon.doe@company.com|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| |steve.smith@company.com|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
Run Code Online (Sandbox Code Playgroud)

我需要做到这一点:

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

305|Jon| |Doe|11111|11111@t| |jon.doe@company.com|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| |steve.smith@company.com|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
Run Code Online (Sandbox Code Playgroud)

注意第一行我是如何删除所有这些 | 的。理想情况下,我想在导出文件的查询中执行此操作。消除所有这些的效果| | | 在导出后的第一行?

第一行是静态的,使用以下方法生成:

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
Run Code Online (Sandbox Code Playgroud)

不幸的是,我的大脑一直告诉我这不是一个好主意/不可能。我知道我可以在 .net 中轻松做到这一点,但我不想让另一个程序坐在那里做这些事情。

Sol*_*zky 4

您可以创建 CMD 脚本来创建临时头行文件,运行 BCP,然后将 BCP 输出附加到临时头文件。这将通过 调用,就像当前设置中对BCP 的xp_cmdshell现有调用一样。

这是 CMD 脚本,我将其命名为AddHeaderToExportFile.cmd。它需要两个参数:

  1. 文件名。
  2. 标题行。如果发生变化,只需更新存储过程即可。

只需在 Windows 资源管理器中创建一个新的文本文件,然后将名称(包括 .txt 扩展名)替换为AddHeaderToExportFile.cmd。然后编辑AddHeaderToExportFile.cmd并粘贴以下代码并保存。

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%
Run Code Online (Sandbox Code Playgroud)

调整原始脚本以调用新的 CMD 脚本,新的 SQL 应该类似于:

存储过程:

--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;
Run Code Online (Sandbox Code Playgroud)

或者,您可以创建一个文本文件来保存标题行值,然后完全跳过 CMD 脚本并使用多个调用来xp_cmdshell完成相同的操作:

--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;
Run Code Online (Sandbox Code Playgroud)