Как установить параметр в список значений в отчете 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). вы можете создать заполнитель, который соответствует вашему случаю.