Essbase SQL Interface (for Oracle) ч.3

Забираем данные из APS

Для того что бы забрать данные, нам потребуется две вещи
1) Спецификация протокола XMLA
2) PL_SQL мастерство )
Признаться честно, XMLA я бредил давно, но реально к его познанию меня подтолкнула разработка Василия
Итак, что нам нужно от XMLA

Процесс получения данных через WebService происходит весьма тривиально – вначале метод POST отправляет MDX запрос, затем выбирается полученное множество данных.
Для того что бы отправить MDX запрос, его нужно «упаковать» в XMLA обертку

vTextBuffer:= <?xml version=”1.0″ encoding=”windows-1251″?>
<SOAP-ENV:Body>
<Execute xmlns=”urn:schemas-microsoft-com:xml-analysis”
SOAP-ENV:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”>
<Command>
<Statement>’ ||vMdxQuery||</Statement>
</Command>
<Properties>
<PropertyList>
<DataSourceInfo> Provider=Essbase;Data Source=localhost </DataSourceInfo>
<Content>Data</Content>
<Format>Tabular</Format>
<AxisFormat>CustomFormat</AxisFormat>
<Timeout>300</Timeout>
</PropertyList>
</Properties>
</Execute>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>’;

Для меня ключевыми настройками, упростившим разработку и разбор множества, стали параметры

< Format>Tabular</Format>
<AxisFormat>CustomFormat</AxisFormat>

, которые убирают их XML множество лишней информации
Так же обращаю внимание, что нужно указать имя сервера, который будет обслуживать запрос

<DataSourceInfo> Provider=Essbase;Data Source=localhost

После того как сформировали XMLA пакет, отправляем его в APS

vUtlHttpReq := UTL_HTTP.begin_request(vStrBuff, ‘POST’, ‘HTTP/1.0’);
UTL_HTTP.set_header(vUtlHttpReq, ‘content-type’, ‘text/xml; charset=windows-1251’);
UTL_HTTP.set_header(vUtlHttpReq, ‘content-length’, LENGTH(vTextBuffer));
UTL_HTTP.write_text(vUtlHttpReq, vTextBuffer);
UTL_HTTP.set_transfer_timeout(2147483647);
vUtlHttpResp := UTL_HTTP.get_response(vUtlHttpReq);
DBMS_LOB.createtemporary(vClobBuffer, FALSE);
BEGIN
LOOP

UTL_HTTP.read_text(vUtlHttpResp, vTextBuffer, 32767);
DBMS_LOB.writeappend(vClobBuffer, LENGTH(vTextBuffer), vTextBuffer);

END LOOP;
EXCEPTION
WHEN UTL_HTTP.end_of_body THEN
UTL_HTTP.end_response(vUtlHttpResp);
END;

Здесь приведен классический пример , когда весь вывод APS помещается в CLOB буфер, который затем разбирается. Это хорошо работает для маленькой выборки, для того что бы обрабатывать большие множества, нужно разбирать данные в момент их получения, иначе табличное пространство TEMP заберет все свободное дисковое место.
Затем данные в CLOB нужно преобразовать в вид, который удобно обрабатывать в PLSQL

Colas;Caffeine Free Cola;Profit;Total Expenses;105.000000;

Для этого организуем цикл и будем выбирать данные по тегу ‘row>

— Convert XMLA to Native format

vPos := dbms_lob.instr (vClobBuffer,vDelim,1,1);
vLDelim := length(vDelim);

While( vPos != 0 ) loop

IF (mod(i,2) = 0) THEN
vTextBuffer :=replace( replace(replace(substr (vClobBuffer,1,vPos-2),CHR(13)),CHR(10)),’><'); vPos2 := instr (vTextBuffer,'>‘,1,1);
vStrBuff :=”;
While( vPos2 != 0 ) loop
vTextBuffer := substr ( vTextBuffer,vPos2+1, length(vTextBuffer));
vStrBuff := vStrBuff || substr (vTextBuffer,1, instr (vTextBuffer,<‘,1,1)-1) || ‘;’;
vPos2 := instr (vTextBuffer,’>’,1,1);
end loop;

PIPE ROW (vStrBuff);
j := j+1;
END IF;
vClobBuffer := SubStr(vClobBuffer,vPos+vLDelim,length(vClobBuffer));
vPos := dbms_lob.instr(vClobBuffer,vDelim,1,1);

i := i+1;
end loop;

DBMS_LOB.freetemporary(vClobBuffer);

Собранный код, вы можете забрать из хранилища google