2014-07-18 14 views
9

Mam proste zapytanie:Wstawianie węzła podrzędnego w kolumnie XMLTYPE

WITH xtbl AS (
    SELECT XMLTYPE ('<a><b>1</b></a>') AS xcol 
    FROM DUAL 
) 
SELECT XMLQUERY ('copy $tmp := . 
        modify 
         insert node <c>2</c> 
         into $tmp/a/b 
         return $tmp' 
       PASSING xcol 
       RETURNING CONTENT) AS newxcol 
    FROM xtbl; 

Co staram się zrobić to wstawić węzeł <c> po <b> wewnątrz węzła <a> ale Oracle 12c jest rzucanie ten błąd :

ORA-19114: XPST0003 - error during parsing the XQuery expression: 
      LPX-00801: XQuery syntax error at 'EOF' 
      5 - 
      -^

Chcę wyjście jak:

NEWXCOL 
------------- 
<a> 
    <b>1</b> 
    <c>2</c/> 
</a> 

Próbowałem szukać w Oracle Docs dla zastąpienia appendChildXML i postępować zgodnie z tym przykładem, ale tylko dostałem błąd.

Wiem, że to bardzo proste i brakuje mi czegoś oczywistego. Proszę pomóż.

+0

umm, czy jesteś pewien, że używasz przynajmniej Oracle Database 12c Release 1? Twój komunikat o błędzie wyraźnie stwierdza, że ​​aktualizacja XQuery nie jest obsługiwana. Na podstawie dokumentacji powiązanej z nim została wprowadzona w powyższej wersji. Jakiej wersji Oracle używasz? – dirkk

+0

@dirkk, używam Oracle 12.1.0.1. Zaktualizowałem błąd, który dostaję. – Rachcha

+3

Twoje zapytanie jest w porządku. Po prostu zapomniałeś zamknąć tag dodawanego węzła (''). Ponadto, aby uzyskać pożądany wynik, ścieżka docelowa musi mieć wartość '$ tmp/a', a nie' $ tmp/a/b'. –

Odpowiedz

4

następujący kod powinien pracować do 11 i 12 (przestarzałe):

SELECT insertXMLafter(XMLType('<a><b>1</b><c>3</c></a>'), 
       '/a/b', XmlType('<c>2</c>')) 
    FROM dual; 

sam kod przy użyciu nowego xmlquery składnię:

SELECT XMLQuery('copy $tmp := . modify insert node 
       <c>2</c> 
       after $tmp/a/b 
       return $tmp' 
       PASSING XmlType('<a><b>1</b><c>3</c></a>') RETURNING CONTENT) 
    FROM dual; 

Więcej szczegółów dotyczących xmlquery a także stare nieaktualne funkcje mogą być znaleźć tutaj: http://docs.oracle.com/database/121/ADXDB/app_depr_upd.htm#ADXDB6160

+0

Cześć! Wiedziałem, że ktoś zamieści to jako odpowiedź, ale uważam, że nagrodę należy przyznać tylko wtedy, gdy doda ona znaczącą wartość do pytania i komentarzy. Twoja odpowiedź jest zdecydowanie słuszna, ale chciałbym przyznać nagrodę ręczną tylko wtedy, gdy wyjdziesz poza komentarze i przedstawisz dalsze wyjaśnienia. – Rachcha

+0

Dodałem ten sam kod przy użyciu XMLQuery i link do dokumentacji Oracle, która ma kilka ładnych przykładów, jak przekonwertować składnię Oracle do XMLQuery. Nie sądzę, aby dodać coś więcej, aby rozwiązać to pytanie. – Eggi

+0

Działa dobrze we wszystkich trzech wersjach, o których wspomniałem. +50. – Rachcha

2

Jeden brzydki, ale możliwy sposób użycia tylko jednego zapytania SQL, które działa poprawnie na starszych i Obecne wersje baz danych byłoby użyć metody CASE SQL:

WITH tbl AS 
(SELECT SUBSTR(MAX(version),1,2) as ver, XMLType('<a><b>1</b><c>3</c></a>') as xcol 
    FROM v$instance) 
SELECT 
    CASE WHEN ver < '12' THEN 
     insertXMLafter(xcol, 
       '/a/b', XmlType('<c>2</c>')) 
    ELSE 
     XMLQuery('copy $tmp := . modify insert node 
       <c>2</c> 
       after $tmp/a/b 
       return $tmp' 
       PASSING xcol RETURNING CONTENT) 
    END 
FROM tbl; 

Oczywiście to nie pomoże, jeśli metoda insertXMLafter zostanie usunięta w przyszłych wydaniach bazy danych. To spowodowałoby niepoprawny SQL. Ale na razie będziesz dobry i użyje właściwej metody w odpowiednich wersjach.

+0

cóż, jaki jest sens, jeśli zostanie on unieważniony w nowszej wersji? insertXMLafter jest _deprecated_, ale nie jest on zły ani nie używa XQuery Update right. Jest to bardziej zgodne z normami i lepsze pod tym względem, że jeden jest niezależny od dostawcy, ale to nie usprawiedliwia. Nie widzę żadnej wartości dodanej przy użyciu takiego rozwiązania, jeśli masz ograniczenie konieczności używania tego samego zapytania dla wszystkich różnych wersji. – dirkk

+0

To może, ale nie musi, zostać unieważnione w przyszłych wersjach bazy danych, jeśli Oracle zdecyduje się na de-support, a zatem całkowicie usunąć insertXML. Idealnie radziłbyś sobie z różnymi wywołaniami różnych wersji w samym kodzie, jednak Rachcha poprosił o coś, co działałoby zarówno na 11g, jak i na 12c. Zakładam więc, że ta pierwsza nie jest w tym przypadku opcją. – gvenzl

+0

Tak, ale jeśli zostanie on unieważniony, jeśli insertXMLafter zostanie usunięty, dlaczego po prostu go użyć, bez CASE? Tak czy inaczej, byłaby nieważna w przyszłych wersjach bez tej funkcji. – dirkk

Powiązane problemy