Левое внешнее соединение Oracle XMLTABLE не возвращает результаты, если XPath не существует

В таблице tbl есть столбец xml_data типа XMLTYPE. Рассмотрим следующий XML:

<root>
  <element>
    <id>1</id>
    <data>abc</data>
  </element>
  <element>
    <id>2</id>
    <data>def</data>
  </element>
</root>

Мне нужен оператор выбора, который будет возвращать 1 строку для каждой строки в таблице с 3 столбцами: id1, id2 и id3.

id1 получит значение тега «данные» из узла «элемент», где «id» равен 1. id2 получит значение из узла, где «id» равен 2, и т. д.

Если для определенного идентификатора нет элемента (например, id3 в приведенном выше XML), в этом столбце будет возвращено значение NULL.

Итак, для приведенного выше XML я хочу получить

   id1    id2    id3
   --------------------
1  abc    def    -

Я старался:

select id1.val, id2.val, id3.val
from tbl t,
  xmltable ('/root/element[id=1]'
    passing t.xml_data
    columns val varchar2 (100) path 'data') id1,
  xmltable ('/root/element[id=2]'
    passing t.xml_data
    columns val varchar2 (100) path 'data') id2,
  xmltable ('/root/element[id=3]'
    passing t.xml_data
    columns val varchar2 (100) path 'data') id3;

Но я получаю 0 строк, потому что нет '/root/element[id=3]'.

Я попытался добавить (+):

xmltable ('/root/element[id=3]'
        passing t.xml_data
        columns val varchar2 (100) path 'data') (+) id3;

Это не помогло (ни LEFT OUTER JOIN с ON 1=1).

Я заметил, что если XMLQuery действителен, но «путь» внутри xmltable не существует, он РАБОТАЕТ и возвращается NULL (даже без (+) ), но если сам XQuery не не существует, так как в [id=3] это не работает.

select id1.val, id2.val, id3.val
from tbl t,
  xmltable ('/root/element[id=1]'
    passing t.xml_data
    columns val varchar2 (100) path 'data') id1,
  xmltable ('/root/element[id=2]'
    passing t.xml_data
    columns val varchar2 (100) path 'data') id2,
  xmltable ('/root/element[id=2]'
    passing t.xml_data
    columns val varchar2 (100) path 'doesnt-exist') id3;

Возвращает:

   id1    id2    id3
   --------------------
1  abc    def    -

person Y_sonn    schedule 01.03.2016    source источник


Ответы (2)


Вам не нужны множественные вызовы XMLTable, вы можете переместить выбор элемента в предложение пути к столбцу и иметь три таких предложения:

select x.id1, x.id2, x.id3
from tbl t
cross join
  xmltable ('/root'
    passing t.xml_data
    columns id1 varchar2 (100) path 'element[id=1]/data',
       id2 varchar2 (100) path 'element[id=2]/data',
       id3 varchar2 (100) path 'element[id=3]/data'
) x;

ID1   ID2   ID3 
----- ----- -----
abc   def        
person Alex Poole    schedule 01.03.2016

Надеюсь это поможет

WITH TEMP AS(
SELECT ID,DATA_VALUE
  FROM XMLTABLE('./root/element' PASSING XMLTYPE('<root>
  <element>
    <id>1</id>
    <data>abc</data>
  </element>
  <element>
    <id>2</id>
    <data>def</data>
  </element>
</root>')
COLUMNS ID NUMBER PATH './id',
        DATA_VALUE VARCHAR2(240) PATH './data'))
SELECT (SELECT DATA_VALUE FROM TEMP WHERE ID = 1) ID1, 
      (SELECT DATA_VALUE FROM TEMP WHERE ID = 2) ID2,
      (SELECT DATA_VALUE FROM TEMP WHERE ID = 3) ID3
  FROM DUAL;
person Dinesh V    schedule 01.03.2016