XML导入SQL服务器的噩梦

时间:2018-05-09 21:00:27

标签: sql sql-server xml xslt

我试图从XML文件中导入一大堆数据并且我无法添加相关密钥(存储在"密钥"节点中)以链接SQL服务器中的XML数据。

请考虑下面的XML代码段。

<person>
    <keys>
        <key>xx8546</key>
        <key>yy369</key>
    </keys>

    <sex>f</sex>

   <names>
      <name>
         <prename>Sarah</prename>
         <surname>Connor</surname>
      </name>

      <name>
         <prename>Sarah</prename>
         <surname>Williams</surname>
      </name>
  </names>

  <mmx>
      <spouse-name>
          <prename>John</prename>
          <surname>Wyatt</surname>
      </spouse-name>
      <year-of-marriage>1985</year-of-marriage>
  </mmx>

  <pbx>
     <spouse-name>
        <prename>John</prename>
        <surname>Williams</surname>
     </spouse-name>

     <child-name>
        <prename>Sarah</prename>
        <surname>Bean</surname>
     </child-name>

     <year-of-baptism>2007</year-of-baptism>
 </pbx>
</person>  

我需要将相关密钥添加到每个节点。

这是我的tsql的一部分:

DECLARE @x xml;
DECLARE @hdoc int;

SELECT @x = P
FROM OPENROWSET (BULK 'C:\person.xml', SINGLE_BLOB) AS Person(P)

EXEC sp_xml_preparedocument @hdoc OUTPUT, @x

--Person
SELECT * --into tbl_Person
FROM OPENXML (@hdoc, '/persons/person/names/name', 2)
WITH (
[key]  nvarchar(100)  '../../keys/key', 
prename varchar(100),
surname varchar(100),
sex varchar(50) '../../sex'
)

以上代码仅将第一个键值插入两个结果中,例如<key xx8546 </key>。请你能帮我解决这个令人沮丧的问题。

非常感谢,

BN。

1 个答案:

答案 0 :(得分:1)

FROM OPENXML与相应的SP准备和删除文档已过时,不应再使用。而是使用适当的methods the XML data type provides

元素顺序是XML文档的固有部分。这不是最好的设计,但可以通过相对位置链接信息。如果这里缺少某些东西,显然你会遇到麻烦。

我不明白,<sex>是如何关联的以及<mmx><pbx>在这里做了什么,但你可以走这条路:

DECLARE  @xml XML=
N'<person>
    <keys>
        <key>xx8546</key>
        <key>yy369</key>
    </keys>
    <sex>f</sex>
    <names>
      <name>
         <prename>Sarah</prename>
         <surname>Connor</surname>
      </name>
      <name>
         <prename>Sarah</prename>
         <surname>Williams</surname>
      </name>
    </names>
  </person>';

查询以 inline-tally 开头。键的计数作为派生表返回。在这种情况下,Tally将返回12

现在,您可以使用此运行编号从XML中获取相关数据:

WITH Tally(Nr) AS (SELECT TOP (@xml.value(N'count(/person/keys/key)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values) 
SELECT Nr
      ,@xml.value(N'(/person/keys/key[sql:column("Nr")]/text())[1]','nvarchar(max)') AS PersonKey
      ,@xml.value(N'(/person/names/name[sql:column("Nr")]/prename/text())[1]','nvarchar(max)') AS PersonPrename
      ,@xml.value(N'(/person/names/name[sql:column("Nr")]/surname/text())[1]','nvarchar(max)') AS PersonSurname

       -- this will return the <sex> for both (as there is just one...)
      ,@xml.value(N'(/person/sex/text())[1]',N'nvarchar(max)') AS sex
FROM Tally;

结果

Nr  PersonKey   PersonPrename   PersonSurname   sex
1   xx8546      Sarah           Connor          f 
2   yy369       Sarah           Williams        f