2012-11-27 26 views
5

Mam proste XML w kolumnie XMLZaktualizuj kolumnę XML serwera SQL za pomocą XQUERY?

<Bands> 
    <Band> 
     <Name>beatles</Name> 
     <Num>4</Num> 
     <Score>5</Score> 
    </Band> 
    <Band> 
     <Name>doors</Name> 
     <Num>4</Num> 
     <Score>3</Score> 
    </Band> 
</Bands> 

udało mi się zaktualizować kolumny:

-----just update the name to the id)---- 
    UPDATE tbl1 
    SET [myXml].modify('replace value of (/Bands/Band/Name/text())[1] 
    with sql:column("id")') 

wszystko jest w porządku.

Pytanie # 1

Jak mogę korzystać z tej strony internetowej UDPATE wartość na id+"lalala":

UPDATE tbl1 
    SET [myXml].modify('replace value of (/Bands/Band/Name/text())[1] 
    with sql:column("id") + "lalala"') 

Błąd = XQuery [tbl1.myXml.modify()]: Argument '+' musi być jednym numerycznej prymitywnego typu

Pytanie # 1

Załóżmy, że nie chcę aktualizować pierwszego rekordu ([1]), ale chcę, aby udpate (taka sama aktualizacja jak powyżej) tylko tam, gdzie score>4.

mogę napisać oczywiście w XPath:

replace value of (/Bands/Band[Score>4]/Name/text())[1]

Ale nie chcę, aby to zrobić w XPath. Czy nie ma Normalny sposób to zrobić z klauzula Where?

coś takiego:

UPDATE tbl1 
    SET [myXml].modify('replace value of (/Bands/Band/Name/text())[1] 
    with sql:column("id") where [...score>4...]') 

here is the online sql

Odpowiedz

6

Jeśli chcesz łączenia ciągów należy użyć concat a jeśli id w Twoim przypadku jest liczbą całkowitą trzeba oddać go na ciąg w funkcji concat.

W klauzuli where można filtrować wiersze tabeli w celu aktualizacji, nie można określić, które węzły zaktualizować w XML. Trzeba to zrobić w wyrażeniu xquery. Możesz jednak użyć exist w klauzuli where, aby odfiltrować wiersze, które naprawdę wymagają aktualizacji.

update tbl1 
set myXml.modify('replace value of (/Bands/Band[Score > 4]/Name/text())[1] 
        with concat(string(sql:column("id")), "lalalala")') 
where myXml.exist('/Bands/Band[Score > 4]') = 1 
+1

dlaczego zrobili to "[1]"? Czy nie sądzili, że może chcę zaktualizować 'więcej niż 1 element'? –

+0

@RoyiNamir Dokumentacja, która mówi: "Expression1 musi być statycznym singletonem". jest [tutaj] (http://msdn.microsoft.com/en-us/library/ms190675.aspx). To samo dotyczy 'insert', ale' delete' może usunąć więcej niż jeden węzeł. Naprawdę nie wiem, dlaczego zdecydowali się to zrobić, ale jeśli to było dozwolone, mógłbyś skończyć w dziwnych sytuacjach, w których zmodyfikowane węzły zmieniają predykat, który znalazł węzły, które w pierwszej kolejności wymagały modyfikacji. Jeśli potrzebujesz zaktualizować więcej niż jeden węzeł, musisz to zrobić w pętli while. –

+0

Dzięki. Wybieram tę odpowiedź, ponieważ jest ona mniej długa i bardziej czytelna. Ale bardzo dziękuję za obie odpowiedzi! –

5

Q1:

;with t as (select convert(varchar(10),id) + 'lalala' id2, * from #tbl1) 
    UPDATE t 
    SET [myXml].modify('replace value of (/Bands/Band/Name/text())[1] 
    with sql:column("id2")'); 

Uwaga: Czy zdajesz sobie sprawę, że ta aktualizuje nazwę jedynego imienia pierwszego zespołu, nie wszystkie kołnierz sutanny i togi?

2-te Q1:

Nie, nie możesz. Zwłaszcza od (/Bands/Band[Score<4]/Name/text())[1] (zmieniłem na <) specjalnie skierowany do drzwi Band w twoim przykładzie xml w pytaniu. Z drugiej strony klauzula WHERE będzie działać w całym kodzie XML zamiast na określonym poziomie w ścieżce. na przykład bardzo źle interpretacja:

;with t as (
    select a.*, n.m.value('.','int') Score 
    from #tbl1 a 
    cross apply myXml.nodes('/Bands/Band/Score') n(m) -- assume singular 
) 
    UPDATE t 
    SET [myXml].modify('replace value of (/Bands/Band/Name/text())[1] 
    with sql:column("id")') 
    where Score < 4 

Ponieważ istnieje co najmniej jedno pasmo w xml z wynikiem < 4, XML zostanie zaktualizowany. JEDNAK, ponieważ xml.modify działa tylko RAZEM w pierwszym meczu, nazwa pierwszego zespołu jest aktualizowana, a nie pasująca do filtra wyniku.

Powiązane problemy