Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Usando a variável para definir o caminho no XMLTable no Oracle


Eu corro para este mesmo problema (tanto em 11.2.0.3.0 quanto em 12.1.0.2.0). Parece que você não pode usar uma variável PL/SQL no lugar de XQuery_string em xmltable quando a string de consulta faz referência a um namespace. Observe que você pode usar uma variável PL/SQL se não fizer referência a um namespace (veja o exemplo nº 3 abaixo).

A exceção levantada descrição :

Se o fato de usar uma variável em vez de uma string literal parece ser preterido pelo Oracle. O documento de suporte da Oracle Doc ID 1490150.1 (disponível apenas para clientes pagantes) sugere que há um patch (o caso não é exatamente o mesmo que o nosso, mas muito semelhante), mas o documento também afirma que:
  • usar uma variável em vez de um literal de string não é um comportamento padrão SQL/XML
  • construir XPath/XQuery durante o tempo de execução tem uma severa penalidade de desempenho

E, portanto, a Oracle recomenda usar apenas literais de string.

Minha confusão inicial foi causada pelo seguinte conflito na própria documentação da Oracle (11.2):

Função XMLTABLE SQL/XML no banco de dados XML Oracle em Guia do desenvolvedor de banco de dados XML :

XMLTABLE em Referência de linguagem SQL de banco de dados :

Observe a falta de "como uma string literal" da segunda citação. E é claro que primeiro li apenas Referência da linguagem SQL do banco de dados ...

A documentação do XMLTABLE foi corrigida na versão 12.1 :

Então a resposta é que não use uma variável como XQuery_string até compila e em alguns casos parece funcionar.

Abaixo, você encontrará exemplos mínimos para reproduzir o problema:

Exemplo nº 1

Isso funciona e imprime 'This is A.' como esperado.
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;
/

Exemplo nº 2

Isso falha com:
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;
/

Exemplo nº 3

Isso funciona e imprime 'This is A.' como esperado.
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;
/