2013-06-17 1 views
4

Orders 테이블에 OrderXML이라는 XML 열이 있습니다 ...
비교 (포함) 비교를 수행해야하는 노드를 포함하여 두 노드의 값을 확인하여 SQL Server의 XML 열을 업데이트하는 방법

<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> 

내 최종 목표는 OrderXML 열 IF에서 XML을 수정하는 것입니다 InternalOrderDetails이 같은 많은 InternalOrderDetail 노드가 포함

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

... 테이블에서이 같은 XML의 XPath는 ...입니다 노드의 Item_Number에 다음을 포함합니다. COTRGUID ('% COTRGUID'와 같은)와 PriceLevel = NONFREE. 이 조건이 충족되면 PriceLevel 열을 FREE로 변경하고 싶습니다.

(OrderXML.value 또는 OrderXML.exist 함수를 사용하여) 정확한 노드를 찾는 xpath 표현식을 작성하고 OrderXML.modify 함수를 사용하여 XML을 업데이트하는 데 문제가 있습니다.

내가 where 절에 대해 다음 시도 :

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

작업을 수행하지만, 내가 같은 내 두 번째 조건을 (PriceLevel = 비 자유)를 포함 할 필요가 날 것으로 보인다 where 절 및 나는 그것을하는 방법을 알아낼 수 없다. 아마도 내가 ...에서와 같은 두 번째 조건

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 행이 영향을 미쳤다 고 말했다).

나는 몇 시간 동안 아무 소용이 없었습니다. 도움을 주시면 감사하겠습니다. 감사.

+0

는, 당신을 주어 답을 확인하세요 사람들이 올바른 답을 찾을 수 있도록 안내하거나 자신의 답변을 작성하여 받아 들일 수 있습니다. –

+0

이 중 어느 것도 나에게 필요한 솔루션을 제공하지 못했습니다. 조건이 여러 노드에 해당 될 수있는 경우에도 일치하는 노드) –

답변

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

개 이상의 노드를 가질 수 있다면 한 줄, 몇 가지 가능한 해결책이 있습니다. 각각 하나도별로 우아하지 않습니다. sql fiddle demo

  • 하거나 루프에서 업데이트를 할 수있는 - -

    • 당신은 테이블의 모든 XMLS를 재구성 할 수 있습니다에 대한 좋은 답변이있어하지 않는 경우 sql fiddle demo
  • +0

    좋은 답변입니다.이 기능은 저에게 큰 도움이되었습니다. – rosscj2533

    0

    이렇게하면 고생을 할 수 있습니다.

    #HolderTable을 테이블 이름으로 바꿉니다.

    SELECT T2.myAlias.query('./../PriceLevel[1]').value('.' , 'varchar(64)') as MyXmlFragmentValue 
    FROM #HolderTable 
    CROSS APPLY OrderXML.nodes('/InternalOrderDetails/InternalOrderDetail/Item_Number') as T2(myAlias) 
    
    
    SELECT T2.myAlias.query('.') as MyXmlFragment 
    FROM #HolderTable 
    CROSS APPLY OrderXML.nodes('/InternalOrderDetails/InternalOrderDetail/Item_Number') as T2(myAlias) 
    

    EDIT :

    UPDATE 
        #HolderTable 
    SET 
        OrderXML.modify('replace value of (/InternalOrderDetails/InternalOrderDetail/PriceLevel/text())[1] with "MyNewValue"') 
    WHERE 
        OrderXML.value('(/InternalOrderDetails/InternalOrderDetail/PriceLevel)[1]', 'varchar(64)') = 'FREE' 
    
    print @@ROWCOUNT 
    

    문제 인 [1]에 상술한다. 왜 내가 거기에 넣었습니까?

    다음은 아래 나열된 URL의 문장입니다.

    업데이트되는 대상은 표현식 끝에 "[1]"을 추가하여 경로 표현식에 명시 적으로 지정되는 하나의 노드 여야합니다.

    http://msdn.microsoft.com/en-us/library/ms190675.aspx

    편집 할 수 있습니다.

    나는 당신의 좌절감의 뿌리를 발견했다고 생각합니다. (고침없고, 문제 만).

    두 번째 쿼리가 작동합니다.

    그래서 [1]은 "~ ~ 검색 ~ ~ 첫 번째 노드"라는 ..... 경우가 있다고 생각합니다. ..... (당신과 내가 원하는대로) ...... "사용하지 마십시오. 첫 번째 노드. 일치 항목을 찾은 후 "라고 표시합니다.

    UPDATE 
        #HolderTable 
    SET 
        OrderXML.modify('replace value of (/InternalOrderDetails/InternalOrderDetail/PriceLevel/text())[1] with "MyNewValue001"') 
    WHERE 
        OrderXML.value('(/InternalOrderDetails/InternalOrderDetail/PriceLevel[text() = "NONFREE"])[1]', 'varchar(64)') = 'NONFREE' 
        /* and OrderXML.value('(/InternalOrderDetails/InternalOrderDetail/Item_Number)[1]', 'varchar(64)') like '%COTRGUID' */ 
    
    
    
    UPDATE 
        #HolderTable 
    SET 
        OrderXML.modify('replace value of (/InternalOrderDetails/InternalOrderDetail/PriceLevel/text())[1] with "MyNewValue002"') 
    WHERE 
        OrderXML.value('(/InternalOrderDetails/InternalOrderDetail/PriceLevel[text() = "FREE"])[1]', 'varchar(64)') = 'FREE' 
    
    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 Fiddle

    내가 경우 다음 처리 한 : 문제가 모두 필요 where 절로서
    1.
    2. 노드에서 '% COTRGUID'와 (과) <PriceLevel> = NONFREE 같은 모든 <Item_Number>이 업데이트됩니다.

    데이터와 테이블을 약간 변경해야 할 수도 있습니다.

    +0

    @Seth 스피어 만 :이게 도움이 되나요? –

    관련 문제