Как установить параметр в список значений в отчете BIRT?
У меня есть набор данных с таким запросом:
select s.name, w.week_ending, w.sales
from store s, weekly_sales_summary w
where s.id=w.store_id and s.id = ?
Я хотел бы изменить запрос, чтобы позволить мне указать список идентификаторов магазина, например:
select s.name, w.week_ending, w.sales
from store s, weekly_sales_summary w
where s.id=w.store_id and s.id IN (?)
Как это сделать в BIRT? Какой параметр мне нужно указать?
4 ответов
легкая часть-это параметр отчета: Установите тип отображения в поле списка, затем установите флажок Разрешить несколько значений.
теперь трудная часть: к сожалению, вы не можете привязать параметр отчета с несколькими значениями к параметру dataset (по крайней мере, не в версии 3.2, что я использую). Здесь есть сообщение в блоге BIRT World: http://birtworld.blogspot.com/2009/03/birt-multi-select-statements.html это описывает, как использовать подключаемый модуль кода для привязки мульти-выберите параметры отчета для набора данных отчета.
к сожалению, когда я попробовал, это не сработало. Если вы можете заставить его работать, это метод, который я рекомендовал бы, если вы не можете, то можно было бы изменить queryText набора данных, чтобы вставить все значения из параметра отчета в запрос в соответствующий момент. Предполагая s.id
является числовым, вот функция, которая может быть вставлена в сценарий события beforeOpen для источник:
function fnMultiValParamSql ( pmParameterName, pmSubstituteString, pmQueryText )
{
strParamValsSelected=reportContext.getParameterValue(pmParameterName);
strSelectedValues="";
for (var varCounter=0;varCounter<strParamValsSelected.length;varCounter++)
{
strSelectedValues += strParamValsSelected[varCounter].toString()+",";
}
strSelectedValues = strSelectedValues.substring(0,strSelectedValues.length-1);
return pmQueryText.replace(pmSubstituteString,strSelectedValues);
}
который затем может быть вызван из сценария события beforeOpen для dataset, например:
this.queryText = fnMultiValParamSql ( "rpID", "0 /*rpID*/", this.queryText );
предполагая, что ваш параметр отчета называется rpID. Вам нужно будет изменить свой запрос, чтобы выглядеть так:
select s.name, w.week_ending, w.sales
from store s, weekly_sales_summary w
where s.id=w.store_id and s.id IN (0 /*rpID*/)
0 включается в сценарий, так что сценарий запроса действителен во время разработки, и значения набора данных будут правильно привязаны к отчету; во время выполнения это жестко закодированное 0 будет удаленный.
однако этот подход потенциально очень опасен, так как он может сделать вас уязвимыми для атак SQL-инъекций:http://en.wikipedia.org/wiki/SQL_injection, как показано здесь:http://xkcd.com/327/ .
в случае чисто числовых значений, выбранных из предопределенного раскрывающегося списка, атака SQL-инъекции не должна быть возможной; однако тот же подход уязвим, когда строки ввода freeform для параметра допустимый.
FYI: статья BIRT World должна работать (я ее написал), но это было более раннее решение проблемы.
мы создали плагин с открытым исходным кодом, который вы можете добавить в BIRT, который имеет гораздо более чистое решение этой проблемы. Функция Bind Parameters в birt-functions-lib предоставляет простой способ сделать мульти-выбор из многозначных параметров.
Если вы все еще заинтересованы, посмотрите на birt-функции-проект lib на затмение Лаборатории.
вот еще одна. Основываясь на некоторых подсказках, которые я нашел в другом месте и расширил, чтобы сохранить количество параметров в вашем наборе данных SQL. Это решение работает с функцией JavaScript, которую вы вызываете в OnBeforeOpen набора данных:
prepare(this);
function prepare(dataSet) {
while (dataSet.queryText.indexOf("@IN?")>=0) {
dataSet.queryText = dataSet.queryText.replace(
"@XYZ?",
"('"+params["products"].value.join("','")+"') or ?=0"
);
}
}
в вашем запросе замените вхождения (?) с @XYZ?. Метод выше гарантирует, что запрос имеет фактические значения и все еще параметр (чтобы редактор набора данных и предварительный просмотр не жаловались).
Примечание: остерегайтесь SQL инъекция, например, не разрешая строковые значения
Я создал более общее решение, которое обрабатывает дополнительные параметры, необходимые для поведение тоже. Если параметр не требуется и пользователь не выбирает никакого значения, предложение IN отключается. Он также позволяет пользователю выбирать как реальные значения, так и нулевое значение.
в отчете initialize
скрипт добавляю этот код:
/** Fullfill IN-clause in a data set query,
* using a List box report parameter.
* Placeholder must be the parentheses after IN keyword with wathever you want inside.
* If required is false then the whole IN-clause in the query
* must be surrounded by parentheses.
* dataType and required refers to the parameter, they must be passed,
* but should be better to find a way to retrieve them inside this function
* (given parameter name).
*/
function fulfillInClause(dataSet, placeholder, param, dataType, required) {
if (dataSet.queryText.indexOf(placeholder)>=0) {
var paramValue = params[param].value;
var emptyParam = (paramValue==null || paramValue.length<=0);
//build the list of possible values
// paramValue==null check in ternary operators
// will prevent exceptions when user doesn't select any value
// (it will not affect the query if param is optional,
// while we will never arrive here if it is required)
var replacement = " (";
if (dataType == "string")
replacement += (emptyParam ? "''" : createList(paramValue, ",", "'", "varchar(10)") );
else if (dataType == "integer")
replacement += (emptyParam ? "0" : createList(paramValue, ",", "" , "int" ) );
else
//TODO implement more cases
return;
replacement += ") ";
//if param is not required and user doesn't select any value for it
//then nullify the IN clause with an always-true clause
if (!required && emptyParam)
replacement += " or 0=0 ";
//put replacement in the query
dataSet.queryText = dataSet.queryText.replace( placeholder, replacement );
//DEBUG
params["debug" + dataSet.name + "Query"]=dataSet.queryText;
}
}
/** Create a string list of array values,
* separated by separator and each of them surrounded by a pair surrounders
*/
function createList(array, separator, surrounder, sqlDataType){
var result = "";
for(var i=0; i<array.length; i++) {
if(result.length>0)
result += separator;
if(array[i]!=null)
result += surrounder + array[i] + surrounder;
else
result += "cast(null as " + sqlDataType + ")";
}
return result;
}
пример использования
в запросе набора данных поместите специальное предложение IN -:
select F1, F2
from T1
where F3='Bubi'
and ( F4 in (''/*?customers*/) )
на beforeOpen
сценарий dataset с предложением in напишите:
fulfillInClause(this, "(''/*?customers*/)", "customers", "string", false);
обратите внимание, что я использовал заполнитель, который позволяет выполнять запрос также перед заменой (например. он имеет кавычки, поскольку F4 является varchar). вы можете создать заполнитель, который соответствует вашему случаю.