4

Orders テーブルに OrderXML という xml 列があります... テーブル
にはこのような XML XPath があります...

/Order/InternalInformation/InternalOrderBreakout/InternalOrderHeader/InternalOrderDetails/InternalOrderDetail

InternalOrderDetails には、このような多くの InternalOrderDetail ノードが含まれています...

<InternalOrderDetails>
  <InternalOrderDetail>
    <Item_Number>FBL11REFBK</Item_Number>
    <CountOfNumber>10</CountOfNumber>
    <PriceLevel>FREE</PriceLevel>
  </InternalOrderDetail>
  <InternalOrderDetail>
    <Item_Number>FCL13COTRGUID</Item_Number>
    <CountOfNumber>2</CountOfNumber>
    <PriceLevel>NONFREE</PriceLevel>
  </InternalOrderDetail>
</InternalOrderDetails>

最終目標は、ノードの Item_Number に COTRGUID ('%COTRGUID' など) と PriceLevel=NONFREE が含まれている場合、OrderXML 列の XML を変更することです。その条件が満たされている場合は、PriceLevel 列を FREE に変更したいと考えています。

正しいノードを見つける xpath 式の作成 (OrderXML.value または OrderXML.exist 関数を使用) と、OrderXML.modify 関数を使用した XML の更新の両方に問題があります。

where句について次のことを試しました:

WHERE OrderXML.value('(/Order/InternalInformation/InternalOrderBreakout/InternalOrderHeader/InternalOrderDetails/InternalOrderDetail/Item_Number/node())[1]','nvarchar(64)') like '%13COTRGUID'

それは機能しますが、同じwhere句に2番目の条件(PriceLevel = NONFREE)も含める必要があるように思われ、その方法がわかりません。おそらく、このように 2 番目の条件に AND を入れることができます...

AND OrderXML.value('(/Order/InternalInformation/InternalOrderBreakout/InternalOrderHeader/InternalOrderDetails/InternalOrderDetail/PriceLevel/node())[1]','nvarchar(64)') = 'NONFREE'

しかし、これは XML クエリであるため、最終的に OR のように動作するのではないかと心配しています。

WHERE 句を正しく取得したら、次のように SET を使用して列を更新します。

UPDATE Orders SET orderXml.modify('replace value of (/Order/InternalInformation/InternalOrderBreakout/InternalOrderHeader/InternalOrderDetails/InternalOrderDetail/PriceLevel[1]/text())[1] with "NONFREE"')

ただし、いくつかのテスト データに対してこのステートメントを実行しましたが、更新された XML 列はありませんでした (zz 行が影響を受けたと述べていましたが)。

私はこれで数時間無駄になりました。助けていただければ幸いです。ありがとう。

4

3 に答える 3

4

Orders テーブルの各行に条件を持つノードが複数ない場合は、これを使用できます。

update orders set
    data.modify('
        replace value of 
        (
            /Order/InternalInformation/InternalOrderBreakout/
            InternalOrderHeader/InternalOrderDetails/
            InternalOrderDetail[
                Item_Number[contains(., "COTRGUID")] and
                PriceLevel="NONFREE"
            ]/PriceLevel/text()
        )[1]
        with "FREE"
    ');

sql fiddle demo

1 つの行に複数のノードを配置できる場合、いくつかの解決策が考えられますが、残念ながらどれも本当にエレガントではありません。

  • テーブル内のすべてのxmlを再構築できます-sql fiddle demo
  • または、ループ内で更新を行うことができます - sql fiddle demo
于 2013-08-18T07:41:48.877 に答える
0

これを試して :

;with InternalOrderDetail as (SELECT  id,
       Tbl.Col.value('Item_Number[1]', 'varchar(40)') Item_Number,  
       Tbl.Col.value('CountOfNumber[1]', 'int') CountOfNumber,  
case 
when Tbl.Col.value('Item_Number[1]', 'varchar(40)') like '%COTRGUID'
      and Tbl.Col.value('PriceLevel[1]', 'varchar(40)')='NONFREE'
                   then 'FREE'
else
       Tbl.Col.value('PriceLevel[1]', 'varchar(40)')
end
PriceLevel

FROM   (select id ,orderxml from demo) 
as a cross apply orderxml.nodes('//InternalOrderDetail')
as  
tbl(col) ) ,
cte_data as(SELECT 
  ID,
'<InternalOrderDetails>'+(SELECT ITEM_NUMBER,COUNTOFNUMBER,PRICELEVEL
FROM InternalOrderDetail
where ID=Results.ID
FOR XML AUTO, ELEMENTS)+'</InternalOrderDetails>' as XML_data
FROM InternalOrderDetail Results
GROUP BY ID)
update demo set orderxml=cast(xml_data as xml)
from demo 
inner join cte_data on demo.id=cte_data.id
where cast(orderxml as varchar(2000))!=xml_data;

select * from demo;

SQL フィドル

私は次のケースを処理しました:
1. 必要に応じて、問題の where 句の両方。
2.最初のノードだけでなく、1 つのノードで<Item_Number>「%COTRGUID」および = NONFREE などの すべてを更新します。<PriceLevel>

データとテーブルに若干の変更が必要になる場合があります。

于 2013-06-18T08:43:18.870 に答える