【问题标题】:Exporting SQL data via BCP delimitted HL7通过 BCP 分隔的 HL7 导出 SQL 数据
【发布时间】:2021-02-22 14:38:34
【问题描述】:

我在 $Message 变量中存储了来自 SQL 输出的以下 HL7 消息:

MSH|^~\&|System|System CRM|SYS|System CRM|20210222143236||ADT^A04|CRM001|P|2.4|||AL|NE
EVN||20210222143236
PID||9999999997^^^^NHSN|Ben^Smith^^^Mr||||||12A Cherry Avenue^Middleton^London^Greater London^E170RA^NSP^P|||
PD1|||^Amazing Surgery, Amazing Health Centre, London, E16 0RA|^DR. Fix
PV1|1|O

我正在尝试为其创建 txt 文件的输出:

DECLARE @Message NVARCHAR(MAX)

SET @Message = 'SELECT Message FROM #HL7'

DECLARE @sql VARCHAR(1000);
SELECT @sql = 'bcp ' + @Message + ' queryout "D:\HL7\Test.txt" -c -t|^ , -T -S'+ @@servername
PRINT @sql
EXEC master.dbo.xp_cmdshell @sql 

但是,我似乎收到以下错误

' ' is not recognized as an internal or external command,
operable program or batch file.

当删除 |^ 我得到:

Copy direction must be either 'in', 'out' or 'format'.

请有人帮助我认为分隔导致问题

【问题讨论】:

  • 这就是 SQL 注入攻击的发生方式以及为什么 xp_cmdshell 默认禁用且不应启用的原因。如果 @Message 包含 format c: /u 会发生什么?还是del * /s?停止使用 xp_cmdsel 开始。问题与HL7字符串无关
  • 要了解发生了什么,请检查 @sql 包含的内容:bcp SELECT Message FROM #HL7 queryout .....。这显然是无效的。应引用查询。如果您使用例如 SQL Server 代理或计划任务,您可以只写一行您需要的命令而没有任何安全风险,甚至使用只能从数据库读取和写入特定文件夹的受限帐户
  • 谢谢 我不认为 HL7 消息有问题。它的 BCP 命令。我了解 SQL 注入的风险,您在导出到文件时是否建议使用另一种方法?我确实想到了一个 SSIS 包,但它们创建了数千条这样的消息,并不认为这是最好的选择
  • 如果您了解这些问题,为什么要介绍它们?为什么重新启用xp_cmdshell?该命令默认关闭 15 年,如果不是更长的话。
  • 忽略安全问题,要编写动态 tsql 代码,您需要掌握 tsql 技能,并且您需要查看动态代码在执行时发生错误时生成的内容。我建议您首先编写一个静态 BCP 命令行并让它工作。您将看到尝试使用本地临时表注定要失败,因此您需要解决这个问题。或者更好 - 使用(或研究)ETL 工具。或者重新访问为什么需要将其从数据库导出到文件中 - 也许你不需要?

标签: sql sql-server tsql bcp


【解决方案1】:

试试下面的查询:

SELECT @sql = 'bcp "' + @Message + '" queryout D:\HL7\Test.txt -c -t"|"^ , -T -S'+ @@servername

我刚刚通过以下查询导出了数据:

DECLARE @Message NVARCHAR(MAX)

SET @Message = 'SELECT *FROM test.dbo.table_name'

DECLARE @sql VARCHAR(1000);
SELECT @sql = 'bcp "' + @Message + '" queryout D:\HL7\Test.txt -c -t"|"^ , -T -S'+ @@servername
PRINT @sql
EXEC master.dbo.xp_cmdshell @sql 

【讨论】:

  • 谢谢,太棒了,但认为临时表的使用存在问题。我创建了#HL7,但它不能使用它,但对于普通表它可以
  • 您已经声明了一个只能在当前数据库会话中引用的本地临时表。您可以尝试全局临时表(##HL7)。但这也有一些限制。您可以查看本地和全局临时表。
【解决方案2】:

这是您正在尝试的工作的实现:

-----------------------------------------------------------------
IF OBJECT_ID (N'dbo.spSaveTextToFile') IS NOT NULL
   DROP PROCEDURE dbo.spSaveTextToFile
GO
CREATE PROCEDURE spSaveTextToFile
  @TheString VARCHAR(MAX),
  @Filename VARCHAR(255),
  @Unicode INT=0
AS
  SET NOCOUNT ON
  DECLARE @MySpecialTempTable VARCHAR(255)
  DECLARE @Command NVARCHAR(4000)
  DECLARE @RESULT INT
 
--firstly we create a global temp table with a unique name
  SELECT  @MySpecialTempTable = '##temp'
       + CONVERT(VARCHAR(12), CONVERT(INT, RAND() * 1000000))
--then we create it using dynamic SQL, & insert a single row
--in it with the MAX Varchar stocked with the string we want
  SELECT  @Command = 'create table ['
       + @MySpecialTempTable
       + '] (MyID int identity(1,1), Bulkcol varchar(MAX))
insert into ['
       + @MySpecialTempTable
       + '](BulkCol) select @TheString'
  EXECUTE sp_ExecuteSQL @command, N'@TheString varchar(MAX)',
           @TheString
 
--then we execute the BCP to save the file
  SELECT  @Command = 'bcp "select BulkCol from ['
          + @MySpecialTempTable + ']'
          + '" queryout '
          + @Filename + ' '
         + CASE WHEN @Unicode=0 THEN '-c' ELSE '-w' END
          + ' -T -S' + @@servername
  EXECUTE @RESULT= MASTER..xp_cmdshell @command, NO_OUTPUT
  EXECUTE ( 'Drop table ' + @MySpecialTempTable )
  RETURN @result
  GO

来自The TSQL of Text Files,作者:Phil Factor

【讨论】:

  • 谢谢,我会阅读非常有用的。非常感谢
猜你喜欢
  • 2021-09-10
  • 2016-10-25
  • 1970-01-01
  • 2011-08-20
  • 1970-01-01
  • 1970-01-01
  • 2015-11-28
  • 2011-11-26
  • 2012-04-24
相关资源
最近更新 更多