Oracle
 sql >> Base de données >  >> RDS >> Oracle

Utilisation d'une variable pour définir le chemin dans XMLTable dans Oracle

Je rencontre ce même problème (à la fois dans 11.2.0.3.0 et 12.1.0.2.0). Il semble que vous ne puissiez pas utiliser une variable PL/SQL à la place de XQuery_string sur xmltable lorsque la chaîne de requête fait référence à un espace de noms. Notez que vous pouvez utiliser une variable PL/SQL si vous ne faites pas référence à un espace de noms (voir l'exemple 3 ci-dessous).

L'exception déclenchée description :

Si le fait d'utiliser une variable au lieu d'un littéral de chaîne semble être obsolète par Oracle. Le document d'assistance Oracle Doc ID 1490150.1 (uniquement disponible pour les clients payants) suggère qu'il existe un correctif (le cas n'est pas exactement le même que notre cas mais très similaire) mais le document indique également que :

  • utiliser une variable au lieu d'un littéral de chaîne n'est pas un comportement standard SQL/XML
  • la construction de XPath/XQuery pendant l'exécution a une forte baisse de performances

C'est pourquoi Oracle recommande d'utiliser uniquement des littéraux de chaîne.

Ma confusion initiale a été causée par le conflit suivant dans la propre documentation d'Oracle (11.2) :

Fonction XMLTABLE SQL/XML dans Oracle XML DB dans Guide du développeur XML DB :

XMLTABLE dans Référence du langage SQL de base de données :

Notez le "as a string literal" manquant de la deuxième citation. Et bien sûr, j'ai d'abord lu uniquement Database SQL Language Reference ...

La documentation XMLTABLE a été corrigée dans la version 12.1 :

Donc la réponse est que n'utilisez pas de variable comme XQuery_string même il compile et dans certains cas semble fonctionner.

Vous trouverez ci-dessous des exemples minimaux pour reproduire le problème :

Exemple #1

Cela fonctionne et imprime 'This is A.' comme prévu.

declare
  v_xml constant xmltype := xmltype('
<ns:a
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:ns="http://stackoverflow.com/users/272735/a">
  <foo><bar>This is A.</bar></foo>
</ns:a>
');
  v_content varchar2(100);
begin
  select bar into v_content
  from xmltable(
    xmlnamespaces('http://stackoverflow.com/users/272735/a' as "ns")
    ,'/ns:a/foo' passing v_xml
    columns
    bar varchar2(4000) path 'bar'
  );

  dbms_output.put_line(v_content);
end;
/

Exemple #2

Cela échoue avec :

ORA-19112: error raised during evaluation:
XVM-01081: [XPST0081] Invalid prefix
1   /ns:a/foo
-   ^

declare
  v_xml constant xmltype := xmltype('
<ns:a
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:ns="http://stackoverflow.com/users/272735/a">
  <foo><bar>This is A.</bar></foo>
</ns:a>
');
  v_xquery_string constant varchar2(100) := '/ns:a/foo';
  v_content varchar2(100);
begin
  select bar into v_content
  from xmltable(
    xmlnamespaces('http://stackoverflow.com/users/272735/a' as "ns")
    ,v_xquery_string passing v_xml
    columns
    bar varchar2(4000) path 'bar'
  );

  dbms_output.put_line(v_content);
end;
/

Exemple #3

Cela fonctionne et imprime 'This is A.' comme prévu.

declare
  v_xml constant xmltype := xmltype('<a><foo><bar>This is A.</bar></foo></a>');
  v_xquery_string constant varchar2(100) := '/a/foo';
  v_content varchar2(100);
begin
  select bar into v_content
  from xmltable(
    v_xquery_string passing v_xml
    columns
    bar varchar2(4000) path 'bar'
  );

  dbms_output.put_line(v_content);
end;
/