Tsql 从同一个/另一个表中的另一列向XML列添加属性

Tsql 从同一个/另一个表中的另一列向XML列添加属性,tsql,sql-server-2005,sqlxml,Tsql,Sql Server 2005,Sqlxml,以下是我的设想: --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>&

以下是我的设想:

--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>
我期望的输出如下所示:

   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>`
OrderID OrderCode ShipmentXML
1 ABC
2 XYZ`
如您所见,我正在尝试获取每个
OrderCode
TrackingNumber
DateShipped
,并将它们作为属性。目的是选择,而不是更新

我看到的所有示例都演示了如何使用常量值或变量更新XML。我找不到一个用连接来演示XML更新的。请帮助说明如何实现这一点

更新:


通过“选择不更新”,我的意思是不更新永久表;正如Mikael在第一个答案下面所评论的那样,临时表的更新非常好。

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

xml数据类型的modify()方法只能在集合中使用 UPDATE语句的子句

由于不需要
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

上一个答案是好的,但是您必须明确指定列并将它们转换为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

请参见使用临时表将属性添加到XML的版本的示例

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

或者,您可以将行提取到临时表中,并在那里修改XML(两次),然后查询临时表+1i one和Mikael请参见问题的编辑。我也想看看Mikael的方法。@FMFF我添加了一个这样的版本。这两种方法都是重建XML的聪明方法+1.我的+1也是,我还不熟悉这些技术。在特定情况下,各种方法越多,选择就越丰富。@这种方法的一个优点是,XML中可以有任意数量的其他节点,它们仍然会出现在结果中。您的答案和另一个答案都重建了XML,假设问题中的内容就是所有内容。很可能是这样,只有OP知道。+1,是的,如果XML比世界上的XML更丰富,它可能会很有用question@MikaelEriksson你是绝对正确的;Xml很可能在将来与其他节点一起增长。
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
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