【问题标题】:Reading from XML file into SQL Server从 XML 文件读取到 SQL Server
【发布时间】:2020-06-05 11:03:14
【问题描述】:

我正在尝试读取具有以下架构的物理 xml 文件

    <Document>
<CstmrDrctDbtInitn>
<PmtInf>
  <DrctDbtTxInf>

    <InstdAmt Ccy="EUR">1</InstdAmt>

   <DrctDbtTx>
      <MndtRltdInf>
        <MndtId>umr</MndtId>
        <DtOfSgntr>2020-04-07</DtOfSgntr>
      </MndtRltdInf>
    </DrctDbtTx>
   <Dbtr>
      <Nm>Akings</Nm>
    </Dbtr>

   <DbtrAcct>
      <Id>
        <IBAN>123456789132456789523</IBAN>
      </Id>
    </DbtrAcct>

  </DrctDbtTxInf>   
  </PmtInf>
      </CstmrDrctDbtInitn>
    </Document>

通过使用以下查询:

DECLARE @xml XML
SELECT @xml = BulkColumn
FROM OPENROWSET(BULK 'E:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLELEMOS\MSSQL\Backup\test.xml', SINGLE_BLOB) x
SELECT
  t.c.query('InstdAmt').value('.', 'NVARCHAR(50)'),
   t.c.query('Dbtr/Nm').value('.', 'NVARCHAR(50)')  
FROM @xml.nodes('*:Document/*:CstmrDrctDbtInitn/*:PmtInf/*:DrctDbtTxInf') t(c)

但是每次运行它时我都会得到空白结果,知道我在这里可能缺少什么吗?

【问题讨论】:

  • XML 的根节点是Dcoument,但您在查询中指定了Document。将 XML 或查询更改为一致。
  • 其实我改了还是空白
  • 我在将元素名称更改为 Dcoument 后运行了您的查询,它返回“1 Akings”。
  • 你的真实 XML 中有命名空间吗?
  • 是的,有命名空间,我需要在其他地方声明吗?

标签: sql-server xml tsql openrowset


【解决方案1】:

您可以轻松检查将 XML 的内容读入您的变量是否按预期工作。假设最终成功读取 XML,这应该可以工作:

DECLARE @xml XML =
N'<Document>
  <CstmrDrctDbtInitn>
    <PmtInf>
      <DrctDbtTxInf>
        <InstdAmt Ccy="EUR">1</InstdAmt>
        <DrctDbtTx>
          <MndtRltdInf>
            <MndtId>umr</MndtId>
            <DtOfSgntr>2020-04-07</DtOfSgntr>
          </MndtRltdInf>
        </DrctDbtTx>
        <Dbtr>
          <Nm>Akings</Nm>
        </Dbtr>
        <DbtrAcct>
          <Id>
            <IBAN>123456789132456789523</IBAN>
          </Id>
        </DbtrAcct>
      </DrctDbtTxInf>
    </PmtInf>
  </CstmrDrctDbtInitn>
</Document>';

--直接读取值(如果不重复)

SELECT @xml.value('(/Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf/InstdAmt/text())[1]','int') AS InstAmt
      ,@xml.value('(/Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf/Dbtr/Nm/text())[1]','nvarchar(max)') AS InstAmt;

--阅读 - 在你做的时候 - 使用.nodes()

SELECT t.c.value('(InstdAmt/text())[1]','int') AS InstAmt
      ,t.c.value('(Dbtr/Nm/text())[1]','nvarchar(max)') AS InstAmt
FROM @xml.nodes('/Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf') t(c);

实际上,您自己的代码也可以工作...

命名空间通配符 (*:) 的使用和您的空白结果让我想,您向我们展示的 XML 只是整个事情的一部分。 (如果元素 &lt;Document&gt; 没有出现在其他地方)可能就足够了(如果元素 &lt;Document&gt; 没有出现在其他地方)使用 深度搜索 并在开头加倍 //(=> 以 '//*:Document' 开头)。

更新:如果有(默认)命名空间

从我上面的你的 cmets 来看,有一个默认的命名空间,试试这个:

DECLARE @xml XML =
N'<Document xmlns="someUri">   <!-- adding a default namespace here -->
  <CstmrDrctDbtInitn>
    <PmtInf>
      <DrctDbtTxInf>
        <InstdAmt Ccy="EUR">1</InstdAmt>
        <DrctDbtTx>
          <MndtRltdInf>
            <MndtId>umr</MndtId>
            <DtOfSgntr>2020-04-07</DtOfSgntr>
          </MndtRltdInf>
        </DrctDbtTx>
        <Dbtr>
          <Nm>Akings</Nm>
        </Dbtr>
        <DbtrAcct>
          <Id>
            <IBAN>123456789132456789523</IBAN>
          </Id>
        </DbtrAcct>
      </DrctDbtTxInf>
    </PmtInf>
  </CstmrDrctDbtInitn>
</Document>';

--读取值需要声明命名空间

WITH XMLNAMESPACES(DEFAULT 'someUri')
SELECT @xml.value('(/Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf/InstdAmt/text())[1]','int') AS InstAmt
      ,@xml.value('(/Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf/Dbtr/Nm/text())[1]','nvarchar(max)') AS InstAmt;

使用通配符 *: 也可以,但如果在更复杂的来源中存在名称冲突,则容易出错。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多