Найти тему
Oracle APEX

Печеньки от Oracle. Экспорт/импорт с помощью XML

Перенос данных из систему 1 в систему 2 несколько необычным образом.

Предположим, в системе 1 есть некоторые данные, которые нам надо перенести в систему 2. Предположим, они доступны с использованием следующего запроса:

select arg, func from system1.square_test
;
1 1
2 4
3 9
4 16
5 25
6 36
7 49
8 64
9 81
10 100

Чтоб перенести их традиционным способом, нужно записать DDL создания принимающей таблицы (если ее нет) и скрипт DML для всех строк данных. Что-то типа:

create table system2.square_test (arg number, func number);
insert into system2.square_test (arg, func) values (1, 1);
insert into system2.square_test (arg, func) values (2, 4);
...
insert into system2.square_test (arg, func) values (10, 100);

Конечно, этого никто руками делать не будет, надо записать запросы к системным представлениям, формирующие скрипт, но это довольно долго. Кроме того, в реальности вместо простенькой таблицы square_test может быть некий весьма нетривиальный запрос. А ситуация в реальности такая: "Вот тебе данные - взял и ушел, работать надо!"

Как бы сделать по-быстрому? Например, так:

Первые 2 запроса - в системе 1, остальные - в системе 2
Первые 2 запроса - в системе 1, остальные - в системе 2

Оборачиваем данный нам запрос к системе 1 функцией генерации XML:

select dbms_xmlgen.getXML('
select arg, func from square_test
') as xml
from dual
;

Получаем XML:

<?xml version="1.0"?>
<ROWSET>
<ROW><ARG>1</ARG><FUNC>1</FUNC></ROW>
<ROW><ARG>2</ARG><FUNC>4</FUNC></ROW>
...
<ROW><ARG>10</ARG><FUNC>100</FUNC></ROW>
</ROWSET>

Забираем, отправляем по почте, по WhatsApp или по Skype - покидаем систему 1 и доставляем XML к системе 2.

Поскольку наш XML на момент переноски - это просто текст, причем текст в общем случае длинный, создадим в системе 2 временную приемную таблицу с одним столбцом (и одной строкой) типа CLOB:

create table clob_tmp (clob_data clob)
;

Загрузим в нее наш XML текст. Но CLOB и XML для Oracle - две вещи разные и нам надо преобразовать CLOB в XML:

select xmltype(clob_data) from clob_tmp
;

Создадим еще одну временную таблицу, в которую поместим XML уже в правильном типе XMLtype; создадим прямо из выборки:

create table xml_tmp as
select xmltype(clob_data) as xml_data from clob_tmp
;

Всё, данные находятся в системе 2 - теперь их надо извлечь из XML. Выражение получится довольно заковыристое, но, в общем-то, логичное:

select arg, func
from xml_tmp x
, xmltable(
'/ROWSET/ROW' -- указатель на якоря строк
passing x.xml_data
columns -- спецификация извлекаемых полей:
arg number
, func number
) xt
;
1 1
2 4
...
10 100

Вот наши данные. Теперь мы можем создать приемную таблицу прямо из этой выборки:

create table square_test_receiver as
select arg, func
from xml_tmp x, xmltable('/ROWSET/ROW'
passing x.xml_data columns arg number, func number
) xt
;

Данные готовы к использованию в системе 2.