logo

6 мая 2011 г.

BIEE 10g: Инициализация переменной мультиселект-подсказкой

Довольно часто бывает нужно передать значения из подсказки-multiselect в Direct database request. Но сделать это можно лишь проинициализировав переменную презентации. В стандартной функциональности Oracle BIEE 10g такой возможности нет. Предлагаю воркэраунд. На скриншоте показана возможность добавления предиката в Direct database request по значениям из multiselect-подсказки:



Вот так выглядит подготовленная страница-пример изнутри:


Multiselect-подсказка:

Обратите внимание, что при выборе элемента управления "multi-select" доступна возможность задать имя переменной. Как - будет описано далее.

Direct database request.

Текст запроса:

select t.per_code
from BI_PER_V t
where instr(';'||'@{PARAM1}' ||';', ';' || t.per_code || ';') > 0
and rownum < 10


Вспомогательный ансвер, отображающий значение переменной презентации, проинициализированной мультиселект-подсказкой:


================================================

Как это работает:

1. Позволяем задавать имя переменной при выборе типа подсказки = "multi-select".
Для этого нужно внести небольшое изменение в файл
OracleBI/oc4j_bi/j2ee/home/applications/analytics/analytics/res/b_mozilla/prompts/globalfilterpromptui.js
Найти строку с текстом

if (tFilterNode.getAttribute("eControl") != "multi" &&

и заменить на

if ( 1==1 &&

(старую версию строки закомментируйте)

2. Инициируем переменную заданного типа (презентации, сеанса) строкой - конкатенацией выбранных значений мультиселект-подсказки.
Для этого нужно внести изменение в файл
OracleBI/oc4j_bi/j2ee/home/applications/analytics/analytics/res/b_mozilla/prompts/globalfilterprompt.js
Найдите функцию GFPBuildFilter()
После правки она будет выглядеть так (комментариями "jackcarver" выделены внесенные изменения):

function GFPBuildFilter()
{
var tExpr = XUICreateElement(saw.xml.kSawxNamespace, 'expr');

var tArgs = GFPBuildFilter.arguments;
var tF = new GFPQueryFilter(tArgs[0],tArgs[1]);

var tSQLExpr = XUICreateElement(saw.xml.kSawxNamespace, 'expr');
tSQLExpr.setAttribute("xsi:type", "sawx:sqlExpression");
XUISetElementText(tSQLExpr, tArgs[0]);
tExpr.appendChild(tSQLExpr);

var bNoVal = true;
var sNewOp = tF.sOp;

// MBH6 shows some errors where GFP still has eq for some reason. Most surgical fix
// is to uncomment this check.
if (sNewOp == "eq")
sNewOp = "in";

if (sNewOp == "bet")
sNewOp = "between";

var sType = tArgs[2];

var tValues = new Array();
if (sType == "multi")
tValues = GFPParseArgs(tArgs)
else
{
for (var i = 5; i < tArgs.length; ++i)
{
tValues[tValues.length] = GFPRightTrim(tArgs[i]);
}
}

// is a variable to be set?
var sSetVariable = tArgs[4];

//convert datetime; sTimeZoneOffset is '0' if data type is not datetime or type is 'drop'
var sTimeZoneOffset = tArgs[3];
var nOffset = parseInt(sTimeZoneOffset)
if (nOffset)
{
var tDTP = new DateTimeParser();
for (var i = 0; i < tValues.length; ++i)
{
tValues[i] = saw.tz.parseAndAdjustTimeZoneOffset(tValues[i], nOffset);
}
}

// if more arguments, then values
for (var i = 0; i < tValues.length; ++i)
{
var sVal = tValues[i];

if ((sVal == ksDropDownNone || !sVal) && sNewOp != "between") //if sVal is empty, it is consider the value is not specified. We should not change the operator to NULL in this case.
return;
else if ((sVal == ksDropDownNone || !sVal) && sNewOp == "between")
continue;
else if ((sVal == ksDropDownAllChoices || sVal == ksEditBoxAllChoices) && sNewOp == "between")
{
//treat all choices in between op as blank but always apply the filter
bNoVal = false;
continue;
}

if (sVal == "(All Choices)")
sVal = ksDropDownAllChoices;

// check for null or just whitespace
/*if (sVal == ksDropDownUnspecified)
{
sNewOp = "ignore";
bNoVal = false;
}*/

if (sType == "edit" && sVal == "")
return;

// if all choices
else if ((sVal == ksDropDownAllChoices) || (sVal == ksEditBoxAllChoices))
{
sNewOp = "prompted";
bNoVal = false;
break;
}

// if null
else if (sVal == ksDropDownNull || !sVal)
{
sNewOp = "null";
bNoVal = false;
}

// if they specified a value
else if (sVal != null && (sVal.search(/^\s*$/) == -1))
{
bNoVal = false;
// check for operators we allow user to override
if (sType == "edit" && ((tF.sOp == "in") || (tF.sOp =="like")))
{
// Check for operator
if (sVal.search(/^=/) != -1)
{
sNewOp = "in"
sVal = sVal.replace(/^=\s*/,"");
}
else if (sVal.search(/^<>/) != -1)
{
sNewOp = "notIn";
sVal = sVal.replace(/^<>\s*/,"");
}
else if (sVal.search(/^<=/) != -1)
{
sNewOp = "lessOrEqual";
sVal = sVal.replace(/^<=\s*/,"");
}
else if (sVal.search(/^>=/) != -1)
{
sNewOp = "greaterOrEqual";
sVal = sVal.replace(/^>=\s*/,"");
}
else if (sVal.search(/^</) != -1)
{
sNewOp = "less";
sVal = sVal.replace(/^<\s*/,"");
}
else if (sVal.search(/^>/) != -1)
{
sNewOp = "greater";
sVal = sVal.replace(/^>\s*/,"");
}
}
tF.AddPredArg(tExpr, sVal);

}
}

if (bNoVal)
{
// JPR 8/05 - this check is causing problems with between since it was forcing to prompted.
// We can't determine why this sType != "drop" was ever necessary, so we're returning in
// all cases when there is no value
// if (sType != "drop")
return;

// JPR 8/05 - the comment below makes no sense to us, assuming old logic and returning above now
// Change to prompt as ignore prevents users from blanking out an entry.
//tF.sOp = "prompted";
//sNewOp = "prompted";
}

/* if (tF.sOp == "in" && tF.vValues.length == 1)
sNewOp = "equal";
*/
if (tF.sOp == "cany")
sNewOp = "containsAny";
if (tF.sOp == "call")
sNewOp = "containsAll";
if (tF.sOp == "bwith")
sNewOp = "beginsWith";
if (tF.sOp == "ewith")
sNewOp = "endsWith";

// between must have two values
if (sNewOp == "between")
{
var sVal = tValues[0];
var sVal2 = tValues[1];

// var bVal = (sVal && (sVal != ksDropDownAllChoices) && (sVal != ksEditBoxAllChoices));
// var bVal = (sVal2 && (sVal2 != ksDropDownAllChoices) && (sVal2 != ksEditBoxAllChoices));
if (sVal == ksDropDownAllChoices || sVal == ksEditBoxAllChoices || sVal == ksDropDownNone)
sVal = "";

if (sVal2 == ksDropDownAllChoices || sVal2 == ksEditBoxAllChoices || sVal2 == ksDropDownNone)
sVal2 = "";

if (!(sVal && sVal2))
{
if (!sVal && sVal2)
tF.sOp = "lessOrEqual";
else if (sVal && !sVal2)
tF.sOp = "greaterOrEqual";
else
tF.sOp = "prompted";
}
}
else
tF.sOp = sNewOp;

GFPGetOpType(tExpr, tF.sOp);
//tExpr.setAttribute("xsi:type", sType);
tExpr.setAttribute("op", tF.sOp);

//jackcarver start

if (sType == "multi" && null != sSetVariable && sSetVariable != "") {

var tMultiExpr = XUICreateElement(saw.xml.kSawxNamespace, 'expr');
tMultiExpr.setAttribute("xsi:type", "sawx:logical");
tMultiExpr.setAttribute("op", "and");
tMultiExpr.appendChild(tExpr);

var tVariableExpr = XUICreateElement(saw.xml.kSawxNamespace, 'expr');
tVariableExpr.setAttribute("xsi:type", "sawx:list");
tVariableExpr.setAttribute("op", "in");
tVariableExpr.setAttribute("setVariable", sSetVariable);

var tVarSQLExpr = XUICreateElement(saw.xml.kSawxNamespace, 'expr');
tVarSQLExpr.setAttribute("xsi:type", "sawx:sqlExpression");
XUISetElementText(tVarSQLExpr, "DUMMY_TABLE.DUMMY_COL");
tVariableExpr.appendChild(tVarSQLExpr);

sValue = tValues.join(";");

var tValueExpr = XUICreateElement(saw.xml.kSawxNamespace, 'expr');
tValueExpr.setAttribute("xsi:type", "sawx:untypedLiteral");
XUISetElementText(tValueExpr, sValue);
tVariableExpr.appendChild(tValueExpr);


tMultiExpr.appendChild(tVariableExpr);

return tMultiExpr;
}

//jackcarver end

if (null != sSetVariable && sSetVariable != "")
XUISetAttributeString(tExpr, "setVariable", sSetVariable);

return tExpr;
}


Это все.
Надеюсь, кому-то статья поможет.

9 комментариев:

  1. Добрый день! А как это заставить работать в кластерной архитектуре с включенным SSO? Попробовали сделать как описано на обоих нодах кластера - не работает.

    ОтветитьУдалить
  2. На 10.1.3.4.2 скрипт не работает. Видимо что-то поменяли внутри. Ругается вот так при задании значения промта и переходе:
    Dashboard Display Error
    The property 'varchar' cannot be set on the specified object
    Error Details
    Error Codes: OKSCUA6Y:SDKE4UTF
    Expression: varchar='Aileen Smith'

    Не подскажете, в чем может быть проблема ?

    ОтветитьУдалить
  3. Can you send me files globalfilterpromptui.js,
    globalfilterprompt.js ?

    ОтветитьУдалить
  4. Добрый день!

    Изменила файлы, как указано в Вашей статье. Выполнила Redeploy analytics.ear. Но возможность задания переменной при множественном выборе так и не появилась...

    С уважением, Вера

    ОтветитьУдалить
  5. В продолжении предыдущего коммента:
    оказывается, что в Mosilla FireFox и в Internet Explorer всё работает, не работает пока что только в Google Chrome.

    С уважением, Вера

    ОтветитьУдалить
  6. Нет под рукой BI10g.
    Попробуйте сравнить содержимое POST-запросов (при срабатывании мультиселект-подсказки) в Firefox(с помощью Firebug) и в Chrome (с помощью Chrome Developer tools)

    ОтветитьУдалить
  7. Добрый день!
    Не нашла, где сравнивать и в какой момент? После нажатия "Перейти"? Какой тег нужно копировать?
    Простите меня за такие вопросы, просто я в HTML и Java Script практически по нулям...

    С уважением, Вера

    ОтветитьУдалить
  8. В Firefox используйте Firebug и панель Net http://getfirebug.com/network

    В Chrome используйте Developer tools и панель Network
    https://developers.google.com/chrome-developer-tools/docs/network
    (не забудьте включить запись http://superuser.com/questions/395919/where-is-the-post-tab-in-chrome-developer-tools-network)

    Ваша задача состоит в том, чтобы отследить какое содержимое передается на сервер браузером в момент нажатия кнопки "Перейти". И попытаться понять разницу и ее причину для различных браузеров.

    ОтветитьУдалить
  9. Не получается... Наверное, придется смириться.

    С уважением, Вера Солнцева

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