Вы можете использовать цепочечные вызовы XMLTable:
select t1.name, t1.age, t2.some_number
from my_with_clause
cross join xmltable (
'/root/person'
passing xmltype(my_with_clause.my_xml)
columns name varchar2(20) path 'name',
age number path 'age',
list_of_numbers xmltype path 'list_of_numbers/number'
) t1
cross join xmltable (
'/number'
passing t1.list_of_numbers
columns some_number number path '.'
) t2;
NAME AGE SOME_NUMBER
-------------------- ---------- -----------
Miguel Martins 32 1
Miguel Martins 32 2
Another Person 19 3
Another Person 19 4
SQL Fiddle это не нравится , но db <> fiddle делает , и это работает локально против 11gR2. (На самом деле SQL Fiddle в порядке с реальной таблицей вместо CTE ...)
или
select t1.name, t1.age, t2.some_number
from my_with_clause
cross join xmltable (
'/root/person'
passing xmltype(my_with_clause.my_xml)
columns name varchar2(20) path 'name',
age number path 'age',
list_of_numbers xmltype path 'list_of_numbers'
) t1
cross join xmltable (
'/list_of_numbers/number'
passing t1.list_of_numbers
columns some_number number path '.'
) t2;
db <> fiddle
С помощью этого XML вы также можете сделать это с одной XMLTable, начиная с чисел и затем просматривая узлы для других данных:
select t1.name, t1.age, t1.some_number
from my_with_clause
cross join xmltable (
'/root/person/list_of_numbers/number'
passing xmltype(my_with_clause.my_xml)
columns name varchar2(20) path './../../name',
age number path './../../age',
some_number number path '.'
) t1;
NAME AGE SOME_NUMBER
-------------------- ---------- -----------
Miguel Martins 32 1
Miguel Martins 32 2
Another Person 19 3
Another Person 19 4
SQL Fiddle и db <> fiddle .
, но ваш реальный (не минимальный) XML может не сделать это практичным.
Это также работает с таблицами с несколькими строками, а не только с CTE или таблицей с одним значением XML для распаковки.
Если у вас может быть сценарий, в котором list_of_names
отсутствует или пуст, и вы все еще хотите показать имя / возраст, вы можете использовать внешнее объединение вместо перекрестного, но для этого нужно уродливое предложение on 1=1
. SQL Fiddle , показывающий перекрестное соединение и левое соединение для такого рода данных, но я бы не стал использовать этот подход с левым соединением, если вы можете.
Если вы используете 12 c или выше, вы можете использовать outer apply
вместо left join ... on 1=1
, что довольно менее оскорбительно. (И если вам не нужно беспокоиться о пропущенных номерах, вы можете использовать cross apply
вместо cross join
, как показало @Lukasz - похоже, здесь ничего не изменится.)
ORA-19025 интересно. SQL Fiddle работает Oracle База данных 11g Express Edition, выпуск 11.2.0.2.0. В Enterprise Edition 11.2.0.4 ваш код получает
ORA-19279: XPTY0004 - XQuery dynamici c несоответствие типов: ожидаемая одноэлементная последовательность - получена последовательность из нескольких элементов
вместо этого, но это та же проблема; под каждым человеком есть несколько number
узлов, и он не знает, что с ними делать, как тип данных по умолчанию - поскольку вы не указали типы данных, все возвращается в виде строк. В моей первой версии я использую тот же путь, но объявляю этот столбец как XMLType, поэтому вы получаете числа в виде фрагмента XML, как в первой версии:
<number>1</number><number>2</number>
или во второй :
<list_of_numbers><number>1</number><number>2</number></list_of_numbers>
Затем они могут быть использованы цепным вызовом XMLTable.