2013-08-06 41 views
2

这里是我的方案添加到XML列的属性:从另一列在同一个/另一个表

--ORDER table 
OrderID OrderCode DateShipped ShipmentXML 
1  ABC  08/06/2013  <Order><Item CustomerName="BF" City="Philadelphia" State="PA"></Item></Order> 
2  XYZ  08/05/2013  <Order><Item CustomerName="TJ" City="Richmond" State="VA"></Item></Order> 

在过程中的某个时刻,我会知道这些订单分别TrackingNumber。跟踪号码另一个表可用这样的:

--TRACKING table 
TrackingID OrderCode TrackingNumber  
98   ABC   1Z1    
99   XYZ   1Z2 

我期待的输出如下:

OrderID OrderCode  ShipmentXML 
    1  ABC   <Order><Item CustomerName="BF" City="Philadelphia" State="PA" DateShipped="08/06/2013" TrackingNumber="1Z1"></Item></Order> 
    2  XYZ   <Order><Item CustomerName="TJ" City="Richmond" State="VA" DateShipped="08/05/2013" TrackingNumber="1Z2"></Item></Order>` 

正如你所看到的,我试图让TrackingNumberDateShipped每个OrderCode并将它们作为属性。意图是一个SELECT,而不是UPDATE。

我见过的所有示例演示了如何使用常量值或变量更新XML。我无法找到一个用JOIN演示XML更新的人。请帮助完成这项工作。

UPDATE:

通过 '选择不更新',我的意思是永久表中没有更新;因为Mikael在第一个答案下面评论,所以临时表的更新非常好。

回答

3

一个版本。

select OrderID, 
     OrderCode, 
     DateShipped, 
     ShipmentXML 
into #Order 
from [Order] 

update #Order 
set ShipmentXML.modify 
    ('insert attribute DateShipped {sql:column("DateShipped")} 
    into (/Order/Item)[1]') 

update O 
set ShipmentXML.modify 
    ('insert attribute TrackingNumber {sql:column("T.TrackingNumber")} 
    into (/Order/Item)[1]') 
from #Order as O 
    inner join Tracking as T 
    on O.OrderCode = T.OrderCode 

select OrderID, 
     OrderCode, 
     ShipmentXML 
from #Order 

drop table #Order 
+0

+1。在各种情况下更丰富的选择更丰富的选择。 –

+1

@ i-one这种方法的优点是XML可以有任意数量的其他节点,并且它们仍然会在结果中。您和其他答案都重新构建了XML,假定问题中存在的是全部。而且很可能如此,只有OP知道。 –

+0

+1,是的,如果XML比问题 –

1

我知道允许xml类型的列中的数据的部分修改的唯一方法是使用modify的方法,但如在documentation

xml数据类型的修改()方法中规定只能在使用UPDATE语句的SET 子句。

由于UPDATE不理想,作为一种解决方法我看到的破碎和手动重新组装为:

select 
    o.OrderID, 
    o.OrderCode, 
    (
     cast((select 
      t.c.value('@CustomerName', 'varchar(50)') as '@CustomerName', 
      t.c.value('@City', 'varchar(50)') as '@City', 
      t.c.value('@State', 'varchar(50)') as '@State', 
      o.DateShipped as '@DateShipped', 
      tr.TrackingNumber as '@TrackingNumber' 
     for xml path('Item'), root('Order')) as xml) 
    ) as ShipmentXML 
from 
    [ORDER] o 
    join [TRACKING] tr on tr.OrderCode = o.OrderCode 
    cross apply o.ShipmentXML.nodes('Order/Item') t(c) 

您可能需要应用格式o.DateShipped

+1

或者您可以将行提取到临时表并在那里修改XML(两次),然后查询临时表。 +1 –

+0

i-one&@Mikael请参阅编辑问题。我很想看到Mikael的方法。 – FMFF

+1

@FMFF我添加了一个版本来做到这一点。 –

3

上面的回答很好,但你必须显式地指定列并将它们转换为varchar,这对于未来的支持不太好(如果向ShipmentXML添加属性,则必须修改查询)。
相反,你可以使用XQuery:

select 
    O.OrderID, O.OrderCode, 
    (
     select 
      (select O.DateShipped, T.TrackingNumber for xml raw('Item'), type), 
      O.ShipmentXML.query('Order/*') 
     for xml path(''), type 
    ).query('<Order><Item>{for $i in Item/@* return $i}</Item></Order>') 
from [ORDER] as O 
    left outer join [TRACKING] as T on T.OrderCode = O.OrderCode 
这样

甚至:

select 
    O.OrderID, O.OrderCode, 
    O.ShipmentXML.query(' 
      element Order { 
       element Item { 
        attribute DateShipped {sql:column("O.DateShipped")}, 
        attribute TrackingNumber {sql:column("T.TrackingNumber")}, 
        for $i in Order/Item/@* return $i 
       } 
      }') 
from [ORDER] as O 
    left outer join [TRACKING] as T on T.OrderCode = O.OrderCode 

看到sqlfiddle使用临时表的属性添加到XML实例

+0

这两种聪明的方式重建XML。 +1。 –

+0

我的+1也是,我对这些技术还不熟悉,但还没有 –