2014-07-18 17 views
9

Ho una semplice query:Inserimento di un nodo figlio in una colonna 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; 

Quello che sto cercando di fare è di inserire un nodo <c> dopo <b> all'interno del nodo <a> ma Oracle 12c sta gettando questo errore :

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

voglio l'uscita come:

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

Ho provato a cercare in Oracle Docs per una sostituzione di appendChildXML e seguire quell'esempio, ma ho ricevuto solo l'errore.

So che è molto semplice e mi manca qualcosa di ovvio. Per favore aiuto.

+0

umm, sei sicuro di utilizzare almeno Oracle Database 12c Release 1? Il tuo messaggio di errore indica chiaramente che XQuery Update non è supportato. In base alla documentazione a cui è collegato è stato introdotto con la versione precedente. Quindi, quale versione di Oracle stai usando? – dirkk

+0

@dirkk, sto usando Oracle 12.1.0.1. Ho aggiornato l'errore che sto ottenendo. – Rachcha

+3

La tua query va bene. Hai semplicemente dimenticato la chiusura del tag per il nodo da aggiungere (''). Inoltre, per ottenere il risultato desiderato, il percorso target deve essere '$ tmp/a' non il' $ tmp/a/b'. –

risposta

4

seguito il codice dovrebbe funzionare per 11 e 12 (deprecato):

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

Stesso codice utilizzando la nuova sintassi XMLQUERY:

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; 

Maggiori dettagli riguardanti XMLQUERY e anche le vecchie funzioni deprecate possono essere trovato qui: http://docs.oracle.com/database/121/ADXDB/app_depr_upd.htm#ADXDB6160

+0

Ciao! Sapevo che qualcuno avrebbe postato questo come una risposta, ma credo che un premio dovrebbe essere assegnato solo se aggiunge un valore significativo alla domanda e ai commenti. La tua risposta è sicuramente giusta, ma premetterei la taglia manuale solo se superi i commenti e fornisci ulteriori spiegazioni. – Rachcha

+0

Ho aggiunto lo stesso codice utilizzando XMLQuery e il collegamento alla documentazione Oracle che contiene alcuni esempi su come convertire la sintassi di Oracle in XMLQuery. Non penso ci sia molto altro da aggiungere per risolvere questa domanda. – Eggi

+0

Funziona bene su tutte e tre le versioni che ho menzionato. +50. – Rachcha

2

un modo brutto ma possibile utilizzare solo una query SQL che funziona correttamente su più vecchio e versioni del database attuali sarebbe quella di utilizzare il metodo dei casi in 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; 

Naturalmente questo non vi aiuterà se il metodo insertXMLafter viene rimosso nelle future versioni del database. Ciò produrrebbe un SQL non valido. Ma per ora saresti bravo e userai il metodo giusto nelle versioni giuste.

+0

beh, qual è il punto se diventa non valido con una versione più recente? insertXMLafter è _deprecated_, ma non è sbagliato, né sta usando XQuery Update a destra. È più conforme agli standard e meglio in questo senso che uno è più indipendente dal venditore, ma questo non lo rende giusto. Non vedo alcun valore aggiunto nell'usare tale soluzione se si dispone della restrizione di dover utilizzare la stessa query per tutte le diverse versioni. – dirkk

+0

Bene, può o non può diventare non valido nelle future versioni del database se Oracle decide di rimuovere il supporto e quindi rimuovere insertXMLafter del tutto. Idealmente dovresti gestire chiamate diverse a versioni diverse all'interno del codice stesso, tuttavia, Rachcha ha chiesto qualcosa che avrebbe funzionato sia su 11g che su 12c. Quindi presumo che il primo non sia un'opzione in questo caso. – gvenzl

+0

Sì, ma se diventa non valido se viene rimosso insertXMLafter, perché non utilizzarlo semplicemente, senza CASE? In entrambi i casi, non sarebbe valido nelle versioni future senza questa funzionalità. – dirkk

Problemi correlati