Mam XML
kolumnę zawierającą dane o podobnej strukturze:
<Root>
<Elements>
<Element Code="1" Value="aaa"></Element>
<Element Code="2" Value="bbb"></Element>
<Element Code="3" Value="ccc"></Element>
</Elements>
</Root>
Jak mogę zmodyfikować dane za pomocą programu SQL Server, aby zmienić każdy Value
atrybut w element?
<Root>
<Elements>
<Element Code="1">
<Value>aaa</Value>
</Element>
<Element Code="2">
<Value>bbb</Value>
</Element>
<Element Code="3">
<Value>ccc</Value>
</Element>
</Elements>
</Root>
Aktualizacja:
Mój XML wygląda mniej więcej tak:
<Root attr1="val1" attr2="val2">
<Elements>
<Element Code="1" Value="aaa" ExtraData="extra" />
<Element Code="2" Value="bbb" ExtraData="extra" />
<Element Code="3" Value="ccc" ExtraData="extra" />
<Element Code="4" Value="" ExtraData="extra" />
<Element Code="5" ExtraData="extra" />
</Elements>
<ExtraData>
<!-- Some XML is here -->
</ExtraData>
</Root>
Chciałbym tylko przenieść Value
atrybut i zachować wszystkie inne atrybuty i elementy.
sql-server
xml
xquery
Wojteq
źródło
źródło
<Value>
elementów na każdy<Element>
. Jeśli nie, przeniesienie atrybutu do elementu powoduje, że XML jest bardziej rozdęty i być może mniej wydajny.<Value>
elementu lub zamiast niego.Odpowiedzi:
Możesz zniszczyć XML i odbudować go ponownie za pomocą XQuery.
Wynik:
Jeśli
Elements
nie jest to pierwszy element wRoot
zapytaniu, należy go zmodyfikować, aby dodać wszystkie elementy przedElements
pierwszym i wszystkie elementyElements
po nim.źródło
Możesz także użyć metod typu danych XML (np. Modyfikować ) i niektórych XQuery, aby zmodyfikować plik XML, np.
Ta metoda nie jest dobrze skalowalna w stosunku do dużych fragmentów XML, ale może być lepsza niż hurtowa zamiana XML.
Możesz także łatwo dostosować tę metodę, jeśli kod XML jest przechowywany w tabeli. Znów z doświadczenia nie zaleciłbym uruchomienia pojedynczej aktualizacji dla tabeli milionów wierszy. Jeśli twoja tabela jest duża, rozważ uruchomienie kursora lub w inny sposób grupowanie aktualizacji. Oto technika:
źródło
AKTUALIZACJA:
Zaktualizowałem kod, a także wejściowy i wyjściowy XML w przykładowym zapytaniu poniżej, aby odzwierciedlić najnowsze wymaganie, określone w komentarzu do dokładnej odpowiedzi @ Mikael , która brzmi:
Chociaż pojedyncze wyrażenie może poprawnie pasować do tej nowej odmiany, nie wydaje się, aby można było pominąć pusty
<Value/>
element w jednym przejściu, ponieważ logika warunkowa nie jest dozwolona w ciągu zastępującym. Tak więc dostosowałem to do modyfikacji 2-częściowej: jedno przejście, aby uzyskać niepuste@Value
atrybuty, i jedno przejście, aby uzyskać puste@Value
atrybuty. Nie było potrzeby radzenia sobie z<Element>
brakującym@Value
atrybutem, ponieważ pożądane jest, aby i tak nie mieć<Value>
elementu.Jedną z opcji jest traktowanie XML jako zwykłego ciągu i przekształcanie go na podstawie wzorca. Można to łatwo osiągnąć za pomocą wyrażeń regularnych (w szczególności funkcji „Zamień”), które można udostępnić za pomocą kodu SQLCLR.
W poniższym przykładzie użyto skalarnego UDF RegEx_Replace z biblioteki SQL # (której jestem autorem, ale ta funkcja RegEx jest dostępna w wersji darmowej wraz z wieloma innymi):
Te
PRINT
stwierdzenia są tam po prostu zrobić dla łatwiejszego porównania side-by-side w zakładce „Komunikaty”. Wynikowy wynik to (nieco zmodyfikowałem oryginalny XML, aby było bardzo jasne, że dotknięto tylko pożądanych części i nic więcej):Jeśli chcesz zaktualizować pole w tabeli, możesz dostosować powyższe w następujący sposób:
źródło
Prawdopodobnie istnieją lepsze sposoby wykonania tego poza SQL Server. Oto jeden ze sposobów na zrobienie tego.
Xml CTE przekształca zmienną xml w tabelę.
Główny wybór następnie przekształca CTE z powrotem w XML.
Można to również zrobić za pomocą
For XML Explicit
.źródło