Пример использования
Рассмотрим пример построения отчета в Oracle BI Suite EE на основе тестовой базы данных, которая поставляется с Oracle Express - demo.db. Возьмем куб - SALES, построенный по трем измерениям: MONTH, PRODUCT, DISTRICT. В представленных ниже листингах отсутствует Java-код для шлюзового RMI-сервера, RMI-клиента, поскольку они достаточно большие и сложные.
Создадим для него соответствующие структуры в СУБД Oracle:
----------------------------------------------- -- Спецификация объектного типа для ячейки куба ----------------------------------------------- create or replace type t_sales_row as object ( sales number, month date, product varchar2(30), district varchar2(30) ); ----------------------------------------------- -- Спецификация табличного типа ----------------------------------------------- create or replace type t_sales_table as table of t_sales_row;
Для построения конвейерной табличной функции необходимо создать соответствующий тип, который реализовывал бы интерфейс ODCITable ----------------------------------------------- -- ODCITable тип ----------------------------------------------- create or replace type t_sales_rowset as object ( key integer,
-- Статическая функция, необходимая для создания контекста -- query - эапрос в Express static function ODCITableStart(sctx out t_sales_rowset, query varchar2) return number as language java name 'SalesRowset.ODCITableStart( oracle.sql.STRUCT[], java.lang.String) return java.math.BigDecimal',
-- Метод экземпляра, необходимый для получения очередной порции выборки
member function ODCITableFetch(self in out t_sales_rowset, nrows in number, outset out t_sales_table) return number as language java name 'SalesRowset.ODCITableFetch( java.math.BigDecimal, oracle.sql.ARRAY[]) return java.math.BigDecimal',
-- Метод экхемпляра, необходимый для закрытия контекста
member function ODCITableClose(self in t_sales_rowset) return number as language java name 'SalesRowset.ODCITableClose() return java.math.BigDecimal' );
Теперь нам надо создать Java пакет SalesRowset опишем только основные методы, которые необходимы для работы ODCITable типа.
Первая функция ODCITableStart, необходимая для создания контекста и открытия курсора. Для нее входящим параметром будет Express запрос.
static public BigDecimal ODCITableStart(STRUCT[] sctx, String query) throws SQLException { // Соединение текущей сессии Connection conn = new OracleDriver().defaultConnection(); // Создаем контекст запроса, StoredCtx - произвольный класс, его определяем мы сами StoredCtx ctx = new StoredCtx(query); int key; try { // Создаем ключ для нашего контекста key = ContextManager.setContext(ctx); } catch (CountException ce) { return ERROR; } Object[] impAttr = new Object[1]; impAttr[0] = new BigDecimal(key); // Создаем дескриптор для нашего ODCITable типа в базе StructDescriptor rowset = StructDescriptor.createDescriptor("T_SALES_ROWSET", conn); // Заполняем тип
sctx[0] = new STRUCT(rowset, conn, impAttr); : // Далее мы обращаемся к RMI серверу и отправляем запрос Express : return SUCCESS; }
Вторая функция ODCITableFetch необходима для получения новой порции данных из выборки. Для нее входящим параметром будет Express запрос.
public BigDecimal ODCITableFetch(BigDecimal nrows, ARRAY[] outSet) throws SQLException { StoredCtx ctx; try { // Получаем контекст по ключу ctx = (StoredCtx) ContextManager.getContext(key.intValue()); } catch (InvalidKeyException ik) { return ERROR; } Connection conn = new OracleDriver().defaultConnection(); try { ArrayList list = _srv.fetchQuery(ctx.nQueryId, nrowsval);
StructDescriptor cube_row = StructDescriptor. createDescriptor("T_SALES_ROW", conn); ArrayDescriptor cube_table = ArrayDescriptor. createDescriptor("T_SALES_TABLE",conn); ArrayList list = null; : // Получаем в list через обращение к RMI серверу очередную порцию выборки // Пусть она возвращается в виде // { SALES, MONTH , PRODUCT, DISTRICT}, соответствующим типу t_sales_row
:
Object[] table = new Object[list.size()]; int i = 0; // Проходим по всему массиву и заполняем структуру for (Iterator it = list.iterator(); it.hasNext();) { table[i++] = new STRUCT(_cube_row, _conn, (Object[]) it.next()); } // Создаем массив из структуру outSet[0] = new ARRAY(cube_table, conn, table); table = null; list.clear(); list = null; return SUCCESS;
} catch (Exception e) { e.printStackTrace(); System.out.println(e.toString()); } }
Последняя функция ODCITableClose необходима для закрытия курсора и контекста. public BigDecimal ODCITableClose() throws SQLException { StoredCtx ctx; try { ctx = (StoredCtx) ContextManager.clearContext(key.intValue()); } catch (InvalidKeyException ik) { return ERROR; } : // Обращаемся к RMI серверу и закрываем курсор к Express :
ctx = null; return SUCCESS; }
Теперь можно создать конвейерную табличную функцию, для которой тип T_SALES_ROWSET будет реализующим ее. ---------------------------------------------- -- Конвейерная функция на основе t_sales_rowset ----------------------------------------------- create or replace function getExpressSales(query varchar2) return t_sales_table pipelined using t_sales_rowset;
Теперь для того, чтобы создать представление в СУБД на основе этой функции, нам надо сформировать запрос к Express Server. Для создания SNAPI запросов мы создали специальное приложение Express SNAPI Query Builder, с помощью которого мы соединяемся с Express и строим с помощью стандартного Express мастера запрос.
В итоге получаем запрос к Express Server в следующем виде:
DB0=DEMO.DB\ DBCount=1\ MeasureCount=1\ Measure0=SALES\ E0Count=2\ E1Count=1\ E2Count=1\ E0Dim0Name=XP_MEASUREDIM\ E0Dim0Script=CALL XP_SLLIMIT('XP_MEASUREDIM', 'CUBE','SALES')\ E0Dim1Name=MONTH\ E0Dim1Script=call XP_SELEVALUATE( 'MONTH', NA )\ E0Dim1DimLName=MONTH\ E0Dim1Hier=\ E1Dim0Name=PRODUCT\ E1Dim0Script=call XP_SELEVALUATE( 'PRODUCT', NA )\ E1Dim0DimLName=PRODUCT\ E1Dim0Hier=\ E2Dim0Name=DISTRICT\ E2Dim0Script=call XP_SELEVALUATE( 'DISTRICT', NA )\ E2Dim0DimLName=DISTRICT\ E2Dim0Hier=\ QL=1\
Создаем на его основе представление ---------------------------------------------- -- Представление для SALES ----------------------------------------------- create or replace view v_express_sales as select * from table(getExpressSales('DB0=DEMO.DB\ DBCount=1\MeasureCount=1\Measure0=SALES\E0Count=2\E1Count=1\E2Count=1\E0Dim0Name=XP_MEASUREDIM\ E0Dim0Script=CALL XP_SLLIMIT(''XP_MEASUREDIM'', ''CUBE'',''SALES'')\E0Dim1Name=MONTH\ E0Dim1Script=call XP_SELEVALUATE( ''MONTH'', NA )\E0Dim1DimLName=MONTH\ E0Dim1Hier=\E1Dim0Name=PRODUCT\E1Dim0Script=call XP_SELEVALUATE( ''PRODUCT'', NA )\ E1Dim0DimLName=PRODUCT\E1Dim0Hier=\ E2Dim0Name=DISTRICT\E2Dim0Script=call XP_SELEVALUATE( ''DISTRICT'', NA )\ E2Dim0DimLName=DISTRICT\E2Dim0Hier=\QL=1\'));
Результат запроса
select * from v_express_sales;
SALES MONTH PRODUCT DISTRICT ---------- ----------- ------------------------- ------------------------- 32153,52 31.01.1995 TENTS BOSTON 32536,3 28.02.1995 TENTS BOSTON 43062,75 31.03.1995 TENTS BOSTON 57608,39 30.04.1995 TENTS BOSTON 81149,36 31.05.1995 TENTS BOSTON 88996,35 30.06.1995 TENTS BOSTON 87273,84 31.07.1995 TENTS BOSTON 89379,13 31.08.1995 TENTS BOSTON 71388,47 30.09.1995 TENTS BOSTON 66412,33 31.10.1995 TENTS BOSTON 66013,92 31.01.1995 CANOES BOSTON 76083,84 28.02.1995 CANOES BOSTON 91748,16 31.03.1995 CANOES BOSTON 125594,28 30.04.1995 CANOES BOSTON 126713,16 31.05.1995 CANOES BOSTON 147412,44 30.06.1995 CANOES BOSTON 152727,12 31.07.1995 CANOES BOSTON 126433,44 31.08.1995 CANOES BOSTON 122797,08 30.09.1995 CANOES BOSTON
87272,64 31.10.1995 CANOES BOSTON
Создадим отчет в Oracle BI EE Answers с помощью Direct Request.
Представим результаты запроса в виде кросс-таблицы
Содержание раздела