SQL Server 从XML文档(不是文件)加载数据

x8diyxa7  于 2022-12-26  发布在  其他
关注(0)|答案(1)|浏览(124)

我有很多日志文件,我想通过Talend作业加载到SQL Server数据库中,这样我就可以保留日志,而无需将文件保存在文件系统中(我们每天生成超过3 k的日志文件)。我不想将作业更改为直接写入数据库,因为我不希望作业依赖于可用的DB服务器。
我创建了一个Talend作业,它可以读取日志文件并将其转换为XML文档,然后可以将其发送到SQL Server(2016)存储过程。存储过程已执行,但日志文件的内容未存储在数据库中。
我已经排除了以下可能的原因:

  • 连通性/权限-我已经使用Talend作业使用的帐户登录到SSMS并执行了该过程(减去XML标头,因为我还没有找到让SSMS允许UTF-8的方法)

存储过程为:

ALTER   procedure [myschema].[myProc]
  @logXML as xml,
  @logFile as varchar(max),
  @result as varchar(max) OUT

as

begin
  declare @myAction varchar(max);

  begin try
    begin transaction
      set @myAction = 'inserting log file ' + @logFile;
      insert into [myDB].[mySchema].[myTable]
      (
        JobName,
        LogName,
        RunDate,
        LogLineNum,
        LogLine
      )
      (select logs.value('JobName[1]', 'varchar(500)') as JobName,
              logs.value('LogName[1]', 'varchar(500)') as LogName,
          logs.value('runDate[1]', 'varchar(20)') as runDate,
          lines.value('Number[1]', 'integer') as LogLineNum,
          lines.value('Content[1]', 'varchar(max)') as LogLine
         from @logXML.nodes('/LogFileContents') as l1(logs),
              @logXML.nodes('/LogFileContents/LogLines/Line') as l2(lines)
      );
    commit transaction;
    set @result = 'SUCCESS';
  end try
  begin catch
  if @@TRANCOUNT > 0
    begin
      rollback
      set @result = 'Error ' + @myAction + '.  Error code: ' + @@ERROR;
    end
  end catch
end

Talend作业生成的XML文档如下所示:

<?xml version="1.0" encoding="UTF-8"?> // I do not have control of this - I get this "free" from Talend
<LogFileContents>
  <JobName>myTask</JobName>
  <LogName>myLogFile</LogName>
  <runDate>YYYYMMDDHHmiss</runDate>
  <LogLines>
    <Line>
      <Number>1</Number>
      <Content>1st Log Message</Content>
    </Line>
    <Line>
      <Number>2</Number>
      <Content>2nd Log Message</Content>
    </Line>
    ...
    <Line>
      <Number>Last</Number>
      <Content>Last Log Message</Content>
    </Line>
  </LogLines>
</LogFileContents>

在Talend中,我尝试将XML文档作为文档传递给tDBSP(这会导致Talend错误)。它当前被配置为将XML文档作为字符串传递-我不得不将“sendStringParametersAsUnicode=false”添加到我的连接字符串中(附加参数)来消除“无法切换编码”错误。当我检查调用存储过程的结果时,我得到“成功”。我甚至尝试过让存储的proc为结果传递一个无意义的值,而不是“SUCCESS”。
在存储过程中,我尝试将输入参数更改为varchar(max),然后通过将其转换为XML变量

@logXML as varchar(max),
...
declare @myXML xml = convert(xml, @logXML)
...
  from @myXML.nodes(...) as l1(logs)
       @myXML.nodes(...) as l2(lines)

其也不将文档加载到数据库中。
但是,如果我使用XML文档通过SSMS执行存储过程(唯一的区别是缺少〈?xml...〉文档头):

<LogFileContents>
  <JobName>myTask</JobName>
  <LogName>myLogFile</LogName>
  <runDate>YYYYMMDDHHmiss</runDate>
  <LogLines>
    <Line>
      <Number>1</Number>
      <Content>1st Log Message</Content>
    </Line>
    <Line>
      <Number>2</Number>
      <Content>2nd Log Message</Content>
    </Line>
    ...
    <Line>
      <Number>Last</Number>
      <Content>Last Log Message</Content>
    </Line>
  </LogLines>
</LogFileContents>

全部内容按预期加载(我测试的日志文件有40行,所有40行都显示在数据库中,完全符合我的预期)。
我还回顾了以下链接--但它们是关于处理XML文件的,而不是XML字符串。
Parsing XML Data Into SQL Server
Importing XML file into SQL Server 2000 using OPENROWSET
我觉得在Talend中有些东西没有完全配置好,但我不确定在哪里。任何输入/指导都将非常感谢。

x6492ojm

x6492ojm1#

XML分解除了性能之外没有任何问题。
请参见下文。
所以,看起来这个问题是某种环境相关的(天才?!)。

    • SQL语言**
DECLARE @logXML XML = 
'<?xml version="1.0" encoding="UTF-8"?>
<LogFileContents>
    <JobName>myTask</JobName>
    <LogName>myLogFile</LogName>
    <runDate>YYYYMMDDHHmiss</runDate>
    <LogLines>
        <Line>
            <Number>1</Number>
            <Content>1st Log Message</Content>
        </Line>
        <Line>
            <Number>2</Number>
            <Content>2nd Log Message</Content>
        </Line>...
        <Line>
            <Number>10000</Number>
            <Content>Last Log Message</Content>
        </Line>
    </LogLines>
</LogFileContents>';

SELECT logs.value('(JobName/text())[1]', 'varchar(500)') as JobName
    , logs.value('(LogName/text())[1]', 'varchar(500)') as LogName
    , logs.value('(runDate/text())[1]', 'varchar(20)') as runDate
    , lines.value('(Number/text())[1]', 'integer') as LogLineNum
    , lines.value('(Content/text())[1]', 'varchar(max)') as LogLine
FROM @logXML.nodes('/LogFileContents') as l1(logs)
    , @logXML.nodes('/LogFileContents/LogLines/Line') as l2(lines);
    • 产出**

| 作业名称|日志名称|运行日期|日志行号|日志行|
| - ------| - ------| - ------| - ------| - ------|
| 我的任务|我的日志文件|年月日小时错过|1个|第1条日志消息|
| 我的任务|我的日志文件|年月日小时错过|第二章|第2条日志消息|
| 我的任务|我的日志文件|年月日小时错过|一万|上次日志消息|

相关问题