使用父子关系将动态XML解析为SQL Server表

时间:2014-11-25 21:12:43

标签: sql xml sql-server-2005

我在源表中有一个XML。我需要将这个XML解析为3个具有Parent Child关系的不同表。我可以在C#中做到这一点,但目前我需要在SQL服务器端实现它。 示例xml如下所示:

<ROWSET>
  <ROW>
     <HEADER_ID>5001507</HEADER_ID>
     <ORDER_NUMBER>42678548</ORDER_NUMBER>
     <CUST_PO_NUMBER>LSWQWE1</CUST_PO_NUMBER>
     <CUSTOMER_NUMBER>38087</CUSTOMER_NUMBER>
     <CUSTOMER_NAME>UNIVERSE SELLER</CUSTOMER_NAME>
     <LINE>
       <LINE_ROW>
         <HEADER_ID>5001507</HEADER_ID>
         <LINE_ID>12532839</LINE_ID>
         <LINE_NUMBER>1</LINE_NUMBER>        
         <ITEM_NUMBER>STAGEPAS 600I-CA</ITEM_NUMBER>
         <ORDER_QUANTITY>5</ORDER_QUANTITY>        
       </LINE_ROW>      
       <LINE_ROW>
         <HEADER_ID>5001507</HEADER_ID>
         <LINE_ID>12532901</LINE_ID>
         <LINE_NUMBER>3</LINE_NUMBER>        
         <ITEM_NUMBER>CD-C600 RK</ITEM_NUMBER>
         <ORDER_QUANTITY>6</ORDER_QUANTITY>
       </LINE_ROW>
       <LINE_ROW>
         <HEADER_ID>5001507</HEADER_ID>
         <LINE_ID>12532902</LINE_ID>
         <LINE_NUMBER>4</LINE_NUMBER>
         <ITEM_NUMBER>CD-S300 RK</ITEM_NUMBER>
         <ORDER_QUANTITY>8</ORDER_QUANTITY>
      </LINE_ROW>      
    </LINE>
    <PRCADJ>
      <PRCADJ_ROW>
        <PRICE_ADJUSTMENT_ID>43095064</PRICE_ADJUSTMENT_ID>
        <HEADER_ID>5001507</HEADER_ID>
        <LINE_ID>12532839</LINE_ID>        
        <ADJUSTED_AMOUNT>-126</ADJUSTED_AMOUNT>
      </PRCADJ_ROW>
      <PRCADJ_ROW>
        <PRICE_ADJUSTMENT_ID>43095068</PRICE_ADJUSTMENT_ID>
        <HEADER_ID>5001507</HEADER_ID>
        <LINE_ID>12532840</LINE_ID>
        <ADJUSTED_AMOUNT>-96.6</ADJUSTED_AMOUNT>
      </PRCADJ_ROW>          
    </PRCADJ>
 </ROW>
</ROWSET>

问题是父母可以有多个孩子,每个孩子可以有多个子孩子。如何编写查询以将其传输到Sql Server 2005

2 个答案:

答案 0 :(得分:1)

您需要使用三个CROSS APPLY运算符来分解XML元素列表&#34;到XML行的单独伪表中,因此您可以访问它们的属性 - 如下所示:

SELECT
    HeaderID = XCRow.value('(HEADER_ID)[1]', 'int'),
    OrderNumber = XCRow.value('(ORDER_NUMBER)[1]', 'int'),
    LineHeaderID = XCLine.value('(HEADER_ID)[1]', 'int'),
    LineID = XCLine.value('(LINE_ID)[1]', 'int'),
    LineNumber = XCLine.value('(LINE_NUMBER)[1]', 'int'),
    PriceAdjustmentID = XCPrc.value('(PRICE_ADJUSTMENT_ID)[1]', 'int'),
    AdjustedAmount = XCPrc.value('(ADJUSTED_AMOUNT)[1]', 'decimal(20,4)')
FROM 
    dbo.YourTableNameHere
CROSS APPLY
    Data.nodes('/ROWSET/ROW') AS XTRow(XCRow)
CROSS APPLY
    XCRow.nodes('LINE/LINE_ROW') AS XTLine(XCLine)
CROSS APPLY
    XCRow.nodes('PRCADJ/PRCADJ_ROW') AS XTPrc(XCPrc)

这样,第一个CROSS APPLY将处理直接在<ROWSET> / <ROW>下找到的所有元素(标题信息),第二个将枚举该标题下面的<LINE> / <LINE_ROW>的所有实例第三个CROSS APPLY处理<PRCADJ> / <PRCADJ_ROW>元素,也位于标题下方。

您可能需要略微调整输出 - 我只选择了两个或三个可能的值 - 扩展并适应您自己的需要!但是这应该向您展示基本机制 - .nodes()方法返回一个&#34;伪表&#34; XML片段,每个匹配您定义的XPath表达式。

答案 1 :(得分:1)

你可以做这样的事。使用cross apply,您将获得节点元素,然后使用value子句提取值。你需要指定列类型,即int或varchar等。

然后可以使用insert into select查询插入结果。

insert into Table1 values ( header_id, order_number, cust_po_number)
select R.value('(HEADER_ID)[1]', 'int') As header_id,
       R.value('(ORDER_NUMBER)[1]', 'int') as order_number,
       R.value('(CUST_PO_NUMBER)[1]', 'varchar(256)') as cust_po_number
from table 
cross apply XMLdata.nodes('/ROWSET/ROW') AS P(R)

insert into Table2 values ( header_id, line_id, line_number)
select R.value('(HEADER_ID)[1]', 'int') As header_id,
       R.value('(LINE_ID)[1]', 'int') as line_id,
       R.value('(LINE_NUMBER)[1]', 'int') as line_number
from table 
cross apply XMLdata.nodes('/ROWSET/ROW/LINE/LINE_ROW') AS P(R)