Если бы у вас были уникальные данные, вы могли бы изменить то, что у вас есть сейчас. Но вы также можете извлечь каждый столбец независимо как часть второй таблицы XML:
with ...
SELECT n.att_name AS name,
v.*
FROM response r,
XMLTABLE
(
'//abc-values/attribute'
PASSING r.xm
COLUMNS
att_name VARCHAR2(30) PATH 'name',
value_list XMLTYPE PATH 'value-list'
) n,
XMLTABLE
(
'value-list'
PASSING n.value_list
COLUMNS
contract_status varchar2(30)
PATH 'value/name[text()="CONTRACT_STATUS"]/../value',
contract_status_desc varchar2(30)
PATH 'value/name[text()="CONTRACT_STATUS_DESC"]/../value',
source_system varchar2(30)
PATH 'value/name[text()="SOURCE_SYSTEM"]/../value',
source_value varchar2(30)
PATH 'value/name[text()="SOURCE_VALUE"]/../value',
source_desc varchar2(30)
PATH 'value/name[text()="SOURCE_DESC"]/../value',
visible varchar2(30)
PATH 'value/name[text()="VISIBLE"]/../value',
required varchar2(30)
PATH 'value/name[text()="REQUIRED"]/../value'
) v;
NAME CONTRACT_STATUS CONTRACT_STATUS_DESC SOURCE_SYSTEM SOURCE_VALUE SOURCE_DESC VISIBLE REQUIRED
------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------
7 xyzabc xyzabc xyzabc xyzabc xyzabc xyzabc xyzabc
7 xyzabc xyzabc xyzabc xyzabc xyzabc xyzabc xyzabc
или с одной XMLTable, предполагая один список значений на узел:
SELECT x.*
FROM response r,
XMLTABLE
(
'//abc-values/attribute'
PASSING r.xm
COLUMNS
name VARCHAR2(30) PATH 'name',
contract_status varchar2(30)
PATH 'value-list/value/name[text()="CONTRACT_STATUS"]/../value',
contract_status_desc varchar2(30)
PATH 'value-list/value/name[text()="CONTRACT_STATUS_DESC"]/../value',
source_system varchar2(30)
PATH 'value-list/value/name[text()="SOURCE_SYSTEM"]/../value',
source_value varchar2(30)
PATH 'value-list/value/name[text()="SOURCE_VALUE"]/../value',
source_desc varchar2(30)
PATH 'value-list/value/name[text()="SOURCE_DESC"]/../value',
visible varchar2(30)
PATH 'value-list/value/name[text()="VISIBLE"]/../value',
required varchar2(30)
PATH 'value-list/value/name[text()="REQUIRED"]/../value'
) x;
Чтобы превратить это во вставку, выберите *
из подзапроса, используя это предложение with
, или вместо этого внедрите значение XML в таблицу XML:
INSERT INTO some_table (name, contract_status, contract_status_desc,
source_system, source_value, source_desc, visble, required)
SELECT *
FROM XMLTABLE
(
'//abc-values/attribute'
PASSING xmltype('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><tns:getAbcResponse xmlns:tns="http://xyz.abc.com"><abc-name>CONTRACT_STATUS</abc-name><abc-values>
<attribute><name>7</name><value-list><value><name>CONTRACT_STATUS</name><value>xyzabc</value></value><value><name>CONTRACT_STATUS_DESC</name><value>xyzabc</value></value><value><name>SOURCE_SYSTEM</name><value>xyzabc</value></value><value><name>SOURCE_VALUE</name><value>xyzabc</value></value><value><name>SOURCE_DESC</name><value>xyzabc</value></value><value><name>VISIBLE</name><value>xyzabc</value></value><value><name>REQUIRED</name><value>xyzabc</value></value></value-list></attribute>
<attribute><name>7</name><value-list><value><name>CONTRACT_STATUS</name><value>xyzabc</value></value><value><name>CONTRACT_STATUS_DESC</name><value>xyzabc</value></value><value><name>SOURCE_SYSTEM</name><value>xyzabc</value></value><value><name>SOURCE_VALUE</name><value>xyzabc</value></value><value><name>SOURCE_DESC</name><value>xyzabc</value></value><value><name>VISIBLE</name><value>xyzabc</value></value><value><name>REQUIRED</name><value>xyzabc</value></value></value-list></attribute>
</abc-values><status error-code="0"><error-msg>OK</error-msg></status></tns:getAbcResponse></soapenv:Body></soapenv:Envelope>')
COLUMNS
name VARCHAR2(30) PATH 'name',
contract_status varchar2(30)
PATH 'value-list/value/name[text()="CONTRACT_STATUS"]/../value',
contract_status_desc varchar2(30)
PATH 'value-list/value/name[text()="CONTRACT_STATUS_DESC"]/../value',
source_system varchar2(30)
PATH 'value-list/value/name[text()="SOURCE_SYSTEM"]/../value',
source_value varchar2(30)
PATH 'value-list/value/name[text()="SOURCE_VALUE"]/../value',
source_desc varchar2(30)
PATH 'value-list/value/name[text()="SOURCE_DESC"]/../value',
visible varchar2(30)
PATH 'value-list/value/name[text()="VISIBLE"]/../value',
required varchar2(30)
PATH 'value-list/value/name[text()="REQUIRED"]/../value'
);
... или откуда вы, конечно, получаете это.
Пути находят value/name
узлов с определенными текстовыми значениями, а затем находят смежные value
для каждого конкретного имени. (Синтаксис @ Boneist по сути тот же принцип, но короче и понятнее; не знаю, почему я так долго его проделал! Поэтому вы можете использовать value[name="CONTRACT_STATUS"]/value
в первой версии выше и value-list/value[name="CONTRACT_STATUS"]/value
во второй версии, используя один XMLTable. Я оставлю свои, как это, чтобы показать разницу ...)
Также обратите внимание, что этот подход позволяет вам объявлять подходящий тип данных и размер для каждого из извлеченных значений столбцов, вместо того, чтобы использовать varchar2(30)
для всех них. (Я представляю себе обязательные и видимые флаги, например, с одним символом).