如何使用XML在SQL中保存多行?

时间:2012-06-17 07:52:31

标签: asp.net sql xml sql-server-2008-r2 xquery

我有以下XML,我希望将其数据保存在我的SQL表中。我有一个名为tblDummy的表,它有三列“JobID”“ItemID”“SubitemID”。对于Jobid和Itemid的特定组合,可以有多个子项。我怎么能这样做?

<jobs>
   <job>
     <jobid>4711</jobid>
     <items>
     <itemid>1</itemid>
       <subitems>
        <subitemid>1</subitemid>
        <subitemid>2</subitemid>
       </subitems>
    <itemid>2</itemid>
       <subitems>
        <subitemid>7</subitemid>
        <subitemid>10</subitemid>
       </subitems>
    <itemid>9</itemid>
       <subitems>
        <subitemid>12</subitemid>
        <subitemid>16</subitemid>
       </subitems>
    </items>
   </job>  
 </jobs>

2 个答案:

答案 0 :(得分:1)

正如此XML所示,您无法正确解析它。您需要更改它 - 您应该将每个项目及其itemid和子项目放入单独的<item>节点中 - 否则您只需要一长列<itemid><subitems>您的<items>主节点下的节点,但您无法告知哪些<itemid><subitems>节点属于一起....

您需要将XML更改为:

<job>
   <jobid>4711</jobid>
   <items>
      <item>
         <itemid>1</itemid>
         <subitems>
             <subitemid>1</subitemid>
             <subitemid>2</subitemid>
         </subitems>
      </item>   
      <item>
         <itemid>2</itemid>
          <subitems>
            ......
          </subitems>
      </item>   
      ... (possibly more <item> nodes) ....
   </items>
</job>

然后你可以使用与我之前的问题基本相同的代码 - 扩展到涵盖三个级别:

CREATE PROCEDURE dbo.SaveJobs (@input XML)
AS BEGIN

;WITH JobsData AS
(    
    SELECT
        JobID = JobNode.value('(jobid)[1]', 'int'),
        ItemID = ItemNode.value('(itemid)[1]', 'int'),
        SubItemID = SubItemNode.value('.', 'int')
    FROM 
        @input.nodes('/jobs/job') AS TblJobs(JobNode)
    CROSS APPLY
        JobNode.nodes('items/item') AS TblItems(ItemNode)
    CROSS APPLY
        ItemNode.nodes('subitems/subitem') AS TblSubItems(SubItemNode)
)
INSERT INTO dbo.tblDummy(JobID, ItemID, SubItemID)
   SELECT JobID, ItemID, SubItemID
   FROM JobsData
END

基本上,您需要三个XML节点“列表”:

  • 首先,您需要所有<jobs>/<job>个节点的列表才能获得jobid
  • 对于每个作业节点,您还需要获取嵌套<items>/<item>的列表以获取itemid
  • 从每个节点,您还可以获得<subitems>/<subitem>
  • 的列表

这很可能会奏效 - 但最有可能的是,它会很慢(对.nodes()函数进行三次嵌套调用!)。

更新:

好的,所以第一次调用@input.nodes('/jobs/job') AS TblJobs(JobNode)基本上创建了一个“伪”表TblJobs,其中包含一列JobNode,并且XML中的每个<job>元素都存储在该伪表中的一行 - 所以第一行将在其JobNode列中包含此XML:

<job>
   <jobid>4711</jobid>
   <items>
      <item>
         <itemid>1</itemid>
         <subitems>
             <subitemid>1</subitemid>
             <subitemid>2</subitemid>
         </subitems>
      </item>   
      <item>
         <itemid>2</itemid>
          <subitems>
            ......
          </subitems>
      </item>   
      ... (possibly more <item> nodes) ....
   </items>
</job>

并且每个进一步的行将包含<job>

中每个后续<jobs>元素的其他XML片段

从每个XML片段中,第二个调用

CROSS APPLY JobNode.nodes('items/item') AS TblItems(ItemNode)

再次选择一个XML片段列表到一个伪表(TblItems),其中包含一列ItemNode,其中包含<item><job>个节点的XML片段我们目前正在处理的节点。

因此伪表中的第一行包含:

     <item>
         <itemid>1</itemid>
         <subitems>
             <subitemid>1</subitemid>
             <subitemid>2</subitemid>
         </subitems>
      </item>   

,第二行将包含

      <item>
         <itemid>2</itemid>
          <subitems>
            ......
          </subitems>
      </item>   

等等。

然后第三个调用 - 你已经猜到了 - 再次将XML元素列表作为行提取到伪表中 - XML片段中每个<subitem>节点的一个条目。

更新#2

  

我是新手“JobID = JobNode.value('(jobid)[1]','int')”代码行

好的 - 给出你拥有的<Job> XML片段:

<job>
   <jobid>4711</jobid>
   <items>
     ......
   </items>
</job>

.value()调用只是对该XML执行此XPath表达式(jobid)并基本上返回<jobid>4711</jobid>代码段。然后它提取该节点的(内部文本),.value()调用的第二个参数定义要将其解释为的SQL数据类型 - 因此它基本上抓取了{{ 1}}来自4711节点,并将其解释为<jobid>

答案 1 :(得分:0)

您可以将Jobid和Itemid的复合键作为主键。