【问题标题】:OPENXML import xml to ms sql - namespaceOPENXML 将 xml 导入到 ms sql - 命名空间
【发布时间】:2017-01-19 15:40:03
【问题描述】:

我使用这个网站很长时间了,很多次它帮助我解决了各种问题。 这次我被困住了。我尝试将像下面这样的复杂 xml 导入 ms-sql 表。

<?xml version='1.0' encoding='UTF-8'?>
<S2SCTScf:SCTScfBlkCredTrf xmlns="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf" xmlns:S2SCTScf="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf SCTScfBlkCredTrf.xsd">
  <S2SCTScf:SndgInst>XXXXXXXX</S2SCTScf:SndgInst>
  <S2SCTScf:RcvgInst>YYYYYYYY</S2SCTScf:RcvgInst>
  <S2SCTScf:SrvcId>SCT</S2SCTScf:SrvcId>
  <S2SCTScf:TstCode>P</S2SCTScf:TstCode>
  <S2SCTScf:FType>SCF</S2SCTScf:FType>
  <S2SCTScf:FileRef>AAAAAAAAAAAAAAAAAAA</S2SCTScf:FileRef>
  <S2SCTScf:RoutingInd>IND</S2SCTScf:RoutingInd>
  <S2SCTScf:FileBusDt>2016-11-01</S2SCTScf:FileBusDt>
  <S2SCTScf:FileCycleNo>01</S2SCTScf:FileCycleNo>
  <S2SCTScf:FIToFICstmrCdtTrf xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02">
    <GrpHdr>
      <MsgId>111111111111111111</MsgId>
      <CreDtTm>2016-11-01T15:45:11.0Z</CreDtTm>
      <NbOfTxs>11</NbOfTxs>
      <TtlIntrBkSttlmAmt Ccy="EUR">111111</TtlIntrBkSttlmAmt>
      <IntrBkSttlmDt>2016-11-01</IntrBkSttlmDt>
      <SttlmInf>
        <SttlmMtd>CLRG</SttlmMtd>
        <ClrSys>
          <Prtry>ST2</Prtry>
        </ClrSys>
      </SttlmInf>
      <InstgAgt>
        <FinInstnId>
          <BIC>XXXXXXXX</BIC>
        </FinInstnId>
      </InstgAgt>
      <InstdAgt>
        <FinInstnId>
          <BIC>XXXXXXXX</BIC>
        </FinInstnId>
      </InstdAgt>
    </GrpHdr>
    <CdtTrfTxInf>
      <PmtId>
        <EndToEndId>NOTPROVIDED</EndToEndId>
        <TxId>XXXXXXXXXXXXXXXXXXXXXXXXXX</TxId>
      </PmtId>
      <PmtTpInf>
        <SvcLvl>
          <Cd>SEPA</Cd>
        </SvcLvl>
      </PmtTpInf>
      <IntrBkSttlmAmt Ccy="XXX">1.00</IntrBkSttlmAmt>
      <ChrgBr>SLEV</ChrgBr>
      <Dbtr>
        <Nm>MXXXXXX XXXXXXX</Nm>
        <PstlAdr>
          <Ctry>XX</Ctry>
          <AdrLine>XXXXXXXXXXXXXXXXXXXXXXXXXXX</AdrLine>
        </PstlAdr>
      </Dbtr>
      <DbtrAcct>
        <Id>
          <IBAN>XXXXXXXXXXXXXXXXXXXX</IBAN>
        </Id>
      </DbtrAcct>
      <DbtrAgt>
        <FinInstnId>
          <BIC>XXXXXXXXXXX</BIC>
        </FinInstnId>
      </DbtrAgt>
      <CdtrAgt>
        <FinInstnId>
          <BIC>XXXXXXXXXX</BIC>
        </FinInstnId>
      </CdtrAgt>
      <Cdtr>
        <Nm>XXXXXXXXXXXXXXXXXXXXXXX</Nm>
      </Cdtr>
      <CdtrAcct>
        <Id>
          <IBAN>XXXXXXXXXXXXXXXXXXXXXXX</IBAN>
        </Id>
      </CdtrAcct>
      <RmtInf>
        <Ustrd>XXXXXXXXXXXXXXXXXXXXXXX</Ustrd>
      </RmtInf>
    </CdtTrfTxInf>
    <CdtTrfTxInf>
      <PmtId>
        <EndToEndId>NOTPROVIDED</EndToEndId>
        <TxId>XXXXXXXXXXXXXXXXXXXXXXXXXXXX</TxId>
      </PmtId>
      <PmtTpInf>
        <SvcLvl>
          <Cd>SEPA</Cd>
        </SvcLvl>
      </PmtTpInf>
      <IntrBkSttlmAmt Ccy="XXX">1.00</IntrBkSttlmAmt>
      <ChrgBr>SLEV</ChrgBr>
      <Dbtr>
        <Nm>XXXXXXXXXXXXXXXXX</Nm>
        <PstlAdr>
          <Ctry>XX</Ctry>
          <AdrLine>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</AdrLine>
        </PstlAdr>
      </Dbtr>
      <DbtrAcct>
        <Id>
          <IBAN>XXXXXXXXXXXXXXXXXXXXXXXXX</IBAN>
        </Id>
      </DbtrAcct>
      <DbtrAgt>
        <FinInstnId>
          <BIC>XXXXXXXXXXXXXXXXXXXXXXXX</BIC>
        </FinInstnId>
      </DbtrAgt>
      <CdtrAgt>
        <FinInstnId>
          <BIC>XXXXXXXXXXXXXXXXXXXXXXXX</BIC>
        </FinInstnId>
      </CdtrAgt>
      <Cdtr>
        <Nm>XXXXXXXXXXXXXXXXXXXXXXXX</Nm>
      </Cdtr>
      <CdtrAcct>
        <Id>
          <IBAN>XXXXXXXXXXXXXXXXXXXXXXXXXX</IBAN>
        </Id>
      </CdtrAcct>
      <RmtInf>
        <Ustrd>XXXXXXXXXXXXXXXXXXXXXXXXXXXXX</Ustrd>
      </RmtInf>
    </CdtTrfTxInf>
  </S2SCTScf:FIToFICstmrCdtTrf>
</S2SCTScf:SCTScfBlkCredTrf>

我尝试了 OPENXML 和 XQuery 函数,但在声明和使用命名空间(或命名空间uri)时遇到了一些问题。我不熟悉如此复杂的 xml 和 namespaceuri。我需要一个想法来将下面的数据放到表格中。即使使用一个命名空间,我也成功使用了更简单的 xml。我已经手动删除了前 11 行,下面的选择效果很好......

DECLARE @XML AS XML, @hDoc AS INT, @SQL NVARCHAR (MAX)
SELECT @XML = XMLData FROM XMLwithOpenXML where id=6 --this is the xml without first 11 lines
EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML
SELECT * FROM OPENXML(@hDoc, 'FIToFICstmrCdtTrf/CdtTrfTxInf')
  WITH 
  (
    CCY [varchar](100) 'IntrBkSttlmAmt/@Ccy',
    IntrBkSttlmAmt [varchar](100) 'IntrBkSttlmAmt',
    TxId [varchar](100) 'PmtId/TxId',
    EndToEndId [varchar](100) 'PmtId/EndToEndId',
    ChrgBr [varchar](100) 'ChrgBr'
    --etc
  )
EXEC sp_xml_removedocument @hDoc
GO

【问题讨论】:

    标签: sql xml namespaces xquery sql-server-openxml


    【解决方案1】:

    先说几点

    • FROM OPENXML 已过时,不应再使用(罕见异常退出)
    • 您的 XML 在此处包含显式编码 &lt;?xml version=''1.0'' encoding=''UTF-8''?&gt;。这会迫使你走VARCHAR-path,这在连接非纯拉丁字符时是危险的。最好用utf-16 替换它,然后转到NVARCHAR-path。在这种情况下,您必须在您的 XML 文字前设置一个“N”。
    • 您必须处理相当复杂的命名空间...难以阅读...如果您可以确定没有重复的名称,您可以放弃命名空间声明并在每个名称前面放置一个*:元素。
    • 增加了一些额外的工作:您的内部S2SCTScf:FIToFICstmrCdtTrf 定义了一个新的默认命名空间。我用innerDeflt 给它起了别名。

    这是变量声明

    DECLARE @xml XML=
    '<?xml version=''1.0'' encoding=''UTF-8''?>
    <S2SCTScf:SCTScfBlkCredTrf xmlns="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf" xmlns:S2SCTScf="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf SCTScfBlkCredTrf.xsd">
      <S2SCTScf:SndgInst>XXXXXXXX</S2SCTScf:SndgInst>
      <S2SCTScf:RcvgInst>YYYYYYYY</S2SCTScf:RcvgInst>
      <S2SCTScf:SrvcId>SCT</S2SCTScf:SrvcId>
      <S2SCTScf:TstCode>P</S2SCTScf:TstCode>
      <S2SCTScf:FType>SCF</S2SCTScf:FType>
      <S2SCTScf:FileRef>AAAAAAAAAAAAAAAAAAA</S2SCTScf:FileRef>
      <S2SCTScf:RoutingInd>IND</S2SCTScf:RoutingInd>
      <S2SCTScf:FileBusDt>2016-11-01</S2SCTScf:FileBusDt>
      <S2SCTScf:FileCycleNo>01</S2SCTScf:FileCycleNo>
      <S2SCTScf:FIToFICstmrCdtTrf xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02">
        <GrpHdr>
          <MsgId>111111111111111111</MsgId>
          <CreDtTm>2016-11-01T15:45:11.0Z</CreDtTm>
          <NbOfTxs>11</NbOfTxs>
          <TtlIntrBkSttlmAmt Ccy="EUR">111111</TtlIntrBkSttlmAmt>
          <IntrBkSttlmDt>2016-11-01</IntrBkSttlmDt>
          <SttlmInf>
            <SttlmMtd>CLRG</SttlmMtd>
            <ClrSys>
              <Prtry>ST2</Prtry>
            </ClrSys>
          </SttlmInf>
          <InstgAgt>
            <FinInstnId>
              <BIC>XXXXXXXX</BIC>
            </FinInstnId>
          </InstgAgt>
          <InstdAgt>
            <FinInstnId>
              <BIC>XXXXXXXX</BIC>
            </FinInstnId>
          </InstdAgt>
        </GrpHdr>
        <CdtTrfTxInf>
          <PmtId>
            <EndToEndId>NOTPROVIDED</EndToEndId>
            <TxId>XXXXXXXXXXXXXXXXXXXXXXXXXX</TxId>
          </PmtId>
          <PmtTpInf>
            <SvcLvl>
              <Cd>SEPA</Cd>
            </SvcLvl>
          </PmtTpInf>
          <IntrBkSttlmAmt Ccy="XXX">1.00</IntrBkSttlmAmt>
          <ChrgBr>SLEV</ChrgBr>
          <Dbtr>
            <Nm>MXXXXXX XXXXXXX</Nm>
            <PstlAdr>
              <Ctry>XX</Ctry>
              <AdrLine>XXXXXXXXXXXXXXXXXXXXXXXXXXX</AdrLine>
            </PstlAdr>
          </Dbtr>
          <DbtrAcct>
            <Id>
              <IBAN>XXXXXXXXXXXXXXXXXXXX</IBAN>
            </Id>
          </DbtrAcct>
          <DbtrAgt>
            <FinInstnId>
              <BIC>XXXXXXXXXXX</BIC>
            </FinInstnId>
          </DbtrAgt>
          <CdtrAgt>
            <FinInstnId>
              <BIC>XXXXXXXXXX</BIC>
            </FinInstnId>
          </CdtrAgt>
          <Cdtr>
            <Nm>XXXXXXXXXXXXXXXXXXXXXXX</Nm>
          </Cdtr>
          <CdtrAcct>
            <Id>
              <IBAN>XXXXXXXXXXXXXXXXXXXXXXX</IBAN>
            </Id>
          </CdtrAcct>
          <RmtInf>
            <Ustrd>XXXXXXXXXXXXXXXXXXXXXXX</Ustrd>
          </RmtInf>
        </CdtTrfTxInf>
        <CdtTrfTxInf>
          <PmtId>
            <EndToEndId>NOTPROVIDED</EndToEndId>
            <TxId>XXXXXXXXXXXXXXXXXXXXXXXXXXXX</TxId>
          </PmtId>
          <PmtTpInf>
            <SvcLvl>
              <Cd>SEPA</Cd>
            </SvcLvl>
          </PmtTpInf>
          <IntrBkSttlmAmt Ccy="XXX">1.00</IntrBkSttlmAmt>
          <ChrgBr>SLEV</ChrgBr>
          <Dbtr>
            <Nm>XXXXXXXXXXXXXXXXX</Nm>
            <PstlAdr>
              <Ctry>XX</Ctry>
              <AdrLine>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</AdrLine>
            </PstlAdr>
          </Dbtr>
          <DbtrAcct>
            <Id>
              <IBAN>XXXXXXXXXXXXXXXXXXXXXXXXX</IBAN>
            </Id>
          </DbtrAcct>
          <DbtrAgt>
            <FinInstnId>
              <BIC>XXXXXXXXXXXXXXXXXXXXXXXX</BIC>
            </FinInstnId>
          </DbtrAgt>
          <CdtrAgt>
            <FinInstnId>
              <BIC>XXXXXXXXXXXXXXXXXXXXXXXX</BIC>
            </FinInstnId>
          </CdtrAgt>
          <Cdtr>
            <Nm>XXXXXXXXXXXXXXXXXXXXXXXX</Nm>
          </Cdtr>
          <CdtrAcct>
            <Id>
              <IBAN>XXXXXXXXXXXXXXXXXXXXXXXXXX</IBAN>
            </Id>
          </CdtrAcct>
          <RmtInf>
            <Ustrd>XXXXXXXXXXXXXXXXXXXXXXXXXXXXX</Ustrd>
          </RmtInf>
        </CdtTrfTxInf>
      </S2SCTScf:FIToFICstmrCdtTrf>
    </S2SCTScf:SCTScfBlkCredTrf>';
    

    这就是查询:首先声明所有命名空间。您的节点是 1:1 的纯结构,因此只需在元素名称后添加元素名称即可读取它们,形成 XPath。只有&lt;CdtTrfTxInf&gt; 出现两次,这需要1:n-approachAPPLY.nodes()

    在我的示例中,您可以获得一个模板,用于隐藏在 XML 中的任何类型的数据。剩下的就看你自己了。

    WITH XMLNAMESPACES(DEFAULT  'urn:S2SCTScf:xsd:$SCTScfBlkCredTrf'
                               ,'urn:S2SCTScf:xsd:$SCTScfBlkCredTrf' as S2SCTScf
                               ,'http://www.w3.org/2001/XMLSchema-instance' AS xsi
                               ,'urn:S2SCTScf:xsd:$SCTScfBlkCredTrf SCTScfBlkCredTrf.xsd' AS schemaLocation
                               ,'urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02' AS innerDeflt)
    SELECT rt.value(N'(S2SCTScf:SndgInst)[1]','nvarchar(max)') AS SndgInst
          ,rt.value(N'(S2SCTScf:RcvgInst)[1]','nvarchar(max)') AS RcvgInst
          --more like this
          ,rt.value(N'(S2SCTScf:FIToFICstmrCdtTrf/innerDeflt:GrpHdr/innerDeflt:MsgId)[1]','nvarchar(max)') AS MsgId
          ,rt.value(N'(S2SCTScf:FIToFICstmrCdtTrf/innerDeflt:GrpHdr/innerDeflt:CreDtTm)[1]','datetime') AS CreDtTm
          --more like this
          ,rt.value(N'(S2SCTScf:FIToFICstmrCdtTrf/innerDeflt:GrpHdr/innerDeflt:TtlIntrBkSttlmAmt/@Ccy)[1]','nvarchar(max)') AS TtlIntrBkSttlmAmt_Ccy
          ,rt.value(N'(S2SCTScf:FIToFICstmrCdtTrf/innerDeflt:GrpHdr/innerDeflt:TtlIntrBkSttlmAmt)[1]','int') AS TtlIntrBkSttlmAmt
          --all nodes are 1:1, just "more of the same"
          --But CdtTrfTxInf is there twice, therefore the call to OUTER APPLY rt.nodes()
          ,cti.value(N'(innerDeflt:PmtId/innerDeflt:EndToEndId)[1]','nvarchar(max)') AS EndToEndId
          --all the rest is following the same schema...
    FROM @xml.nodes(N'S2SCTScf:SCTScfBlkCredTrf') AS A(rt) --root
    OUTER APPLY rt.nodes(N'S2SCTScf:FIToFICstmrCdtTrf/innerDeflt:CdtTrfTxInf') AS B(cti) --CdtTrfTxInf
    

    部分结果(字幕转移...)

    SndgInst    RcvgInst    MsgId               CreDtTm     TtlIntrBkSttlmAmt_Ccy   TtlIntrBkSttlmAmt   EndToEndId
    XXXXXXXX    YYYYYYYY    111111111111111111  2016-11-01 15:45:11.000 EUR 111111  NOTPROVIDED
    XXXXXXXX    YYYYYYYY    111111111111111111  2016-11-01 15:45:11.000 EUR 111111  NOTPROVIDED
    

    【讨论】:

    • 哇。这太棒了。谢谢谢谢1000次:))。我只将 TtlIntrBkSttlmAmt 从 int 更改为 decimal,它就像一个魅力。我现在继续在 select 语句中添加我的所有字段。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-03
    • 2012-07-16
    • 1970-01-01
    • 2016-12-29
    • 2018-01-05
    • 1970-01-01
    相关资源
    最近更新 更多