Oracle, XML для вставки заявления - PullRequest
0 голосов
/ 19 ноября 2018

У меня есть образец xml

<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>

В этом примере один тег <attribute> содержит 1 строку, которую мне нужно вставить в таблицу.

Мне удалось создать запрос:

  with response(xm) as ( select 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>')from dual)
SELECT  n.att_name  AS name,
        v.name      AS att_name,
        v.value     AS att_value
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/value'
          PASSING n.value_list
          COLUMNS
            name   varchar2(30) PATH 'name',
            value  varchar2(30) PATH 'value'
        ) v;

При таком подходе мне нужно:

  1. получить первые 7 строк этого запроса,
  2. преобразовать в один запрос вставки -> выполнить / положитьв коллекцию
  3. получить следующие 7 строк этого запроса
  4. и т. д.

Другими словами:

insert

ПРИМЕЧАНИЕ: имя столбца является своего рода идентификатором и повторяется для каждой строки таблицы v.

И я абсолютно не знаю, как этого добиться.Любые идеи, различные подходы будут очень приветствоваться.

Спасибо:)

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

Вот один из способов выбора данных:

with response(xm) as ( select 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>11xyzabc</value></value><value><name>CONTRACT_STATUS_DESC</name><value>12xyzabc</value></value><value><name>SOURCE_SYSTEM</name><value>13xyzabc</value></value><value><name>SOURCE_VALUE</name><value>14xyzabc</value></value><value><name>SOURCE_DESC</name><value>15xyzabc</value></value><value><name>VISIBLE</name><value>16xyzabc</value></value><value><name>REQUIRED</name><value>17xyzabc</value></value></value-list></attribute>
<attribute><name>7</name><value-list><value><name>CONTRACT_STATUS</name><value>21xyzabc</value></value><value><name>CONTRACT_STATUS_DESC</name><value>22xyzabc</value></value><value><name>SOURCE_SYSTEM</name><value>23xyzabc</value></value><value><name>SOURCE_VALUE</name><value>24xyzabc</value></value><value><name>SOURCE_DESC</name><value>25xyzabc</value></value><value><name>VISIBLE</name><value>26xyzabc</value></value><value><name>REQUIRED</name><value>27xyzabc</value></value></value-list></attribute>
</abc-values><status error-code="0"><error-msg>OK</error-msg></status></tns:getAbcResponse></soapenv:Body></soapenv:Envelope>') from dual)
SELECT  n.att_name  AS name,
        v.contract_status,
        v.contract_status_desc,
        v.source_system,
        v.source_value,
        v.source_desc,
        v.visible,
        v.required
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="CONTRACT_STATUS"]/value',
            contract_status_desc varchar2(30) PATH 'value[name="CONTRACT_STATUS_DESC"]/value',
            source_system varchar2(30) PATH 'value[name="SOURCE_SYSTEM"]/value',
            source_value varchar2(30) PATH 'value[name="SOURCE_VALUE"]/value',
            source_desc varchar2(30) PATH 'value[name="SOURCE_DESC"]/value',
            visible varchar2(30) PATH 'value[name="VISIBLE"]/value',
            required varchar2(30) PATH 'value[name="REQUIRED"]/value'
        ) v;

, что дает:

NAME                           CONTRACT_STATUS                CONTRACT_STATUS_DESC           SOURCE_SYSTEM                  SOURCE_VALUE                   SOURCE_DESC                    VISIBLE                        REQUIRED
------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------
7                              11xyzabc                       12xyzabc                       13xyzabc                       14xyzabc                       15xyzabc                       16xyzabc                       17xyzabc
7                              21xyzabc                       22xyzabc                       23xyzabc                       24xyzabc                       25xyzabc                       26xyzabc                       27xyzabc

Затем вы можете просто использовать это в выражении insert into ... (...) select ....

Если это используется в PL / SQL, вы можете просто ссылаться на переменную xmltype в исходном XMLTABLE, вместо того, чтобы использовать подзапрос response, но я ожидаю, что вы уже знали об этом.

0 голосов
/ 19 ноября 2018

Если бы у вас были уникальные данные, вы могли бы изменить то, что у вас есть сейчас. Но вы также можете извлечь каждый столбец независимо как часть второй таблицы 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) для всех них. (Я представляю себе обязательные и видимые флаги, например, с одним символом).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...