logo

27 сент. 2011 г.

BIEE 11g: writeback + Pivot Table

Предыдущая часть.

Механизм обратной записи – writeback – очень удобный инструмент в арсенале OBIEE. И одним из самых естественных примеров его использования является ввод плановых показателей. Но у OBIEE writeback есть существенный минус – он работает только с представлением данных "Таблица". А зачастую просто необходимо видеть не только форму для ввода планов, но и аналогичные плановые данные за прошлые/будущие периоды, т.е. осуществлять ввод плановых показателей через представление "Таблица среза", где столбцы будут элементами измерения календаря.
На примере данных предыдущей части:



В режиме правки видно, что это действительно PivotTable, а не обходные реализации (как например, представление таблицы среза обычной таблицей с заранее определенным количеством столбцов на используемые элементы измерения календаря).


Создать подобную форму совершенно не сложно.
1. Для начала преобразуем тип столбцов для ввода. Нам нужен символьный тип (character).

cast( ifnull("Plan Salesfacts"."Dummy Input", 0) + ifnull("Plan Salesfacts"."Amount Sold", 0) as character)



2. Теперь (так как тип нужных столбцов символьный) мы можем задать формат данных как HTML-конструкцию, обеспечивающую возможность ввода данных.

@[html]<input class="WBInput" type="text" novalue="false" size="10" onchange="obipswb.Grid.Change(event)" onfocus="obipswb.Grid.Focus(event)" value=@H origvalue=@H>



3. Также сделаем небольшой трюк с XML-представлением отчета, который позволит использовать в представлении PivotTable стандартную функциональность writeback (а имеено – создаст кнопки «Apply»/”Revert”). Для этого на вкладке «Advanced» отчета в XML-представлении пропишем в узле <saw:view xsi:type="saw:pivotTableView" name="pivotTableView!1">
Подузел

<saw:displayFormat>
<saw:formatSpec>
<sawwb:writeBack xmlns:sawwb="com.siebel.analytics.web/writeback/v1" xsi:type="sawwb:tableProperties" enabled="true" toggleTableMode="false" templateName="SetPlanSalesProdCatPivot" useTemplate="true" buttonPos="left"/>
</saw:formatSpec>
</saw:displayFormat>

Особую роль тут играет атрибут templateName – задание его значения позволяет использовать XML-шаблон операций insert/update при обратной записи.


4. До сих пор мы не меняли исходных кодов OBIEE. Но сделать это придется: в файлике
Middleware\user_projects\domains\bifoundation_domain\servers\bi_server1\tmp\_WL_user\analytics_11.1.1\7dezjl\war\res\b_mozilla\views\pivot\wbpivotview.js
Требуется внести изменения в функцию obipswb.Grid.UpdateWriteBackActionForEdge

obipswb.Grid.UpdateWriteBackActionForEdge = function (c, f, h) {
var g = false;
var b = c.getWriteBackRows(f);
//jack carver start
if (f == obips.EdgeDefinition.DATA_EDGE) {
for (var d = 0; d < b.length; d++) {
var a = b[d];
if (!a || a.length == 0) {
continue
}
for (var dd = 0; dd < a.length; dd++) {
var aa = a[dd];
if (!aa) {
continue
}
var e = obipswb.Grid.getRecordValues(c, a, f, aa.getCoordinate().getLayer(), aa.getCoordinate().getSlice());

if (obipswb.Grid.shouldDeleteRow(aa)) {
h.deleteRecord(e)
} else {
h.updateRecord(e)
}
g = true
}
}
return g
}
//jack carver end
for (var d = 0; d < b.length; d++) {
var a = b[d];
if (!a || a.length == 0) {
continue
}
var e = obipswb.Grid.getRecordValues(c, a, f, a[0].getCoordinate().getLayer(), a[0].getCoordinate().getSlice());
if (obipswb.Grid.shouldDeleteRow(a)) {
h.deleteRecord(e)
} else {
h.updateRecord(e)
}
g = true
}
return g
};


5. Последний штрих – создание XML-сообщения, сохраняющего изменения в БД.
У меня это сообщение находится в файле Middleware\instances\instance19\bifoundation\OracleBIPresentationServicesComponent\coreapplication_obips1\msgdb\customMessages\MyWritebackTest.xml

<?xml version="1.0" encoding="utf-8"?>
<WebMessageTables xmlns:sawm="com.siebel.analytics.web/message/v1">
<WebMessageTable lang="en-us" system="WriteBack" table="Messages">
<WebMessage name="SetPlanSalesProdCatPivot">
<XML>
<writeBack connectionPool="WriteBack_Connection_Pool">
<insert>MERGE INTO PLAN_SALES_PROD_CAT dst
USING (SELECT ( select min(t.time_id) from TIMES t where t.calendar_month_desc = '@{c_MONTH_DESC}' ) AS time_id,
( select pc.prod_category_id from PROD_CATEGORIES pc where pc.prod_category = '@{c_PROD_CAT}' ) AS prod_category_id
FROM DUAL) src
ON ( src.time_id = dst.time_id AND src.prod_category_id = dst.prod_category_id )
WHEN MATCHED THEN
UPDATE SET dst.amount_sold = nvl('@{c_AMOUNT_SOLD}',dst.amount_sold)
WHEN NOT MATCHED THEN
INSERT
( time_id, prod_category_id, amount_sold )
VALUES
( src.time_id, src.prod_category_id, '@{c_AMOUNT_SOLD}' ) </insert>
<update>MERGE INTO PLAN_SALES_PROD_CAT dst
USING (SELECT ( select min(t.time_id) from TIMES t where t.calendar_month_desc = '@{c_MONTH_DESC}' ) AS time_id,
( select pc.prod_category_id from PROD_CATEGORIES pc where pc.prod_category = '@{c_PROD_CAT}' ) AS prod_category_id
FROM DUAL) src
ON ( src.time_id = dst.time_id AND src.prod_category_id = dst.prod_category_id )
WHEN MATCHED THEN
UPDATE SET dst.amount_sold = nvl('@{c_AMOUNT_SOLD}',dst.amount_sold)
WHEN NOT MATCHED THEN
INSERT
( time_id, prod_category_id, amount_sold )
VALUES
( src.time_id, src.prod_category_id, '@{c_AMOUNT_SOLD}' ) </update>
</writeBack>
</XML>
</WebMessage>
</WebMessageTable>
</WebMessageTables>


Вот и все. Просто, не правда ли!

1 комментарий:

  1. Доброго времени суток!
    по вашей статье внедрили ввод данных в витрины. Все вроде работает, но вылезла одна неприятная вещь: при правке больших объемов данных не все значения сохраняются. Закономерности какой то, почему сохранилось то или другое не нашли.
    Не подскажете куда копать?

    ОтветитьУдалить