BIRT - using report variable to pass data from outer to inner nested data set - eclipse

Hoping someone can tell me what is wrong with this BIRT report. I am trying to use a nested scripted data set, where the outer data set passes data to the inner data set through a report variable.
I find that the report isn't acting as I thought it would. It seems as though the report variable is outputting the last value it has for every row. For the below report I am seeing output such as:
key0
value[9][0]
value[9][1]
value[9][2]
value[9][3]
value[9][4]
key1
value[9][0]
value[9][1]
value[9][2]
value[9][3]
value[9][4]
....
key9
value[9][0]
value[9][1]
value[9][2]
value[9][3]
value[9][4]
Whereas I would expect to see this:
key0
value[0][0]
value[0][1]
value[0][2]
value[0][3]
value[0][4]
key1
value[1][0]
value[1][1]
value[1][2]
value[1][3]
value[1][4]
....
key9
value[9][0]
value[9][1]
value[9][2]
value[9][3]
value[9][4]
My (fully self contained) example report is here: click to see report xml in pastebin.
The key idea is that in the outer data set's fetch, I set the report variable:
vars["values"] = value;
And the inner data set's fetch will grab it:
values = vars["values"].iterator();
and the inner data set's fetch will take data from the report variable:
row["value"] = values.next();

You should be able to use dataSet parameters, to do this. In your example, you'd set up an output parameter in the outer data set's dataset editor. You'd set the value of this parameter to be your values you're passing to the other dataSet.
In the inner dataSet, you'd create an input parameter to take the values. In your layout, you'd need to refresh the bindings on the outer list, so that the output parameter is a binding. Then, you'd go to the binding tab, for the inner list, and choose to pass the outer list's output parameter binding to your input parameter.
Hope this helps.

Related

Passing a column name as an argument for KDB select query?

I would like to pass a column name into a Q function to query a loaded table.
Example:
getDistinct:{[x] select count x from raw}
getDistinct "HEADER"
This doesn't work as the Q documentation says I cannot pass column as arguments. Is there a way to bypass this?
When q interprets x it will treat it as a string, it has no reference to the column, so your output would just be count "HEADER".
If you want to pass in the column as a string you need to build the whole select statement then use value
{value "select count ",x," from tab"} "HEADER"
However, the recommended method would be to use a functional select. Below I use parse to build the functional select equivalent using the parse tree.
/Create sample table
tab:([]inst:10?`MSFT`GOOG`AAPL;time:10?.z.p;price:10?10f)
/Generate my parse tree to get my functional form
.Q.s parse "select count i by inst from tab"
/Build this into my function
{?[`tab;();(enlist x)!enlist x;(enlist `countDistinct)!enlist (#:;`i)]} `inst
Note that you have to pass the column in as a symbol. Additionally the #:i is just the k equivalent to count i.
Update for multiple columns
tab:([]inst:10?`MSFT`GOOG`AAPL;time:10?.z.p;price:10?10f;cntr:10`HK`SG`UK`US)
{?[`tab;();(x)!x;(enlist `countDistinct)!enlist (#:;`i)]} `inst`cntr
To get the functional form of a select statement, I recommend using buildSelect. Also, reduce the scope of parenthesis, i.e. use enlist[`countDistinct] instead of (enlist `countDistinct).

Access locally scoped variables from within a string using parse or value (KDB / Q)

The following lines of Q code all throw an error, because when the statement "local" is parsed, the local variable is not in the correct scope.
{local:1; value "local"}[]
{[local]; value "local"}[1]
{local:1; eval parse "local"}[]
{[local]; eval parse "local"}[1]
Is there a way to reach the local variable from inside the parsed string?
Note: This is a simplification of the actual problem I'm grappling with, which is to write a function that executes a query, accepting a list of columns which it should return. I imagine the finished product looking something like this:
getData:{[requiredColumns, condition]
value "select ",(", " sv string[requiredColumns])," from myTable where someCol=condition"
}
The condition parameter in this query is the one that isn’t recognised and I do realise I could append it’s value rather than reference it inside a string, but the real query uses lots of local variables including tables etc, so it’s not as easy as just pulling all the variables out of the string before calling value on it.
I'm new to KDB and Q, so if anyone has a better way to achieve the same effect I'm happy to be schooled on the proper way to achieve this outcome in Q. Would still be interested to know in the variable access thing is possible though.
In the first example, you are right that local is not within the correct scope, as value is looking for the global variable local.
One way to get around this is to use a namespace, which will define the variable globally, but can only be accessed by calling that namespace. In the modified example below I have defined local in the .ns namespace
{.ns.local:1; value ".ns.local"}[]
For the problem you are facing with selecting, if requiredColumns is a symbol list of columns you can just use the take operator # to select them.
getData:{[requiredColumns] requiredColumns#myTable}
For more advanced queries using variables you may have to use functional select form, explained here. This will allow you to include variables in the where and by clause of the select statement
The same example in functional form would be (no by clause, only select and where):
getData:{[requiredColumns;condition] requiredColumns:(), requiredColumns;
?[myTable;enlist (=;`someCol;condition);0b;requiredColumns!requiredColumns]}
The first line ensures that requiredColumns is a list even if the user enters a single column name
value will look for a variable in the global scope that's why you are getting an error. You can directly use local variables like you are doing that in your function.
Your function is mostly correct, just need a slight correction to append condition(I have mentioned that below). However, a better approach would be to use functional select in this case.
Using functional select:
q) t:([]id:`a`b; val:3 4)
q) gd: {?[`t;enlist (=;`val;y);0b;((),x)!(),x]}
q) gd[`id;3] / for single column
Output:
id
-
1
q) gd[`id`val;3] / for multiple columns
In case your condition column is of type symbol, then enlist your condition value like:
q) gd: {?[`t;enlist (=;`id;y);0b;((),x)!(),x]}
q) gd[`id;enlist `a]
You can use parse to get a functional form of qsql queries:
q) parse " select id,val from t where id=`a"
?
`t
,,(=;`id;,`a)
0b
`id`val!`id`val
Using String concat(your function):
q)getData:{[requiredColumns;condition] value "select ",(", " sv string[requiredColumns])," from t where id=", .Q.s1 condition}
q) getData[enlist `id;`a] / for single column
q) getData[`id`val;`a] / for multi columns

Selecting variables in a dataset according to values in another dataset

I want to create a subset for a dataset which has around 100 variables and I wish to KEEP only those variables that are present as values of another variable in another dataset. Can someone pleae help me with a SPSS Syntax.
This is what it should look like:
DATASET ACTIVATE basedataset.
SAVE OUTFILE ='Newdata.sav'
/KEEP Var1.
Var 1 is the variable in the other dataset which contains all the values based on which i want to perform the subsetting.I am not sure if vector should be involved or if there is an easier way to do this.
The following will create a macro containing the list of variables you require, to use in your analysis or in subsetting the data.
First I'll create some sample data to demonstrate on:
data list free /v1 to v10 (10f3).
begin data
1,2,3,2,4,7,77,777,66,55
end data.
dataset name basedataset.
data list free/var1 (a4).
begin data
"v3", "v5", "v6", "v9"
end data.
dataset name varnames.
Now to create the list:
dataset activate varnames.
write out="yourpath\var1 selection.sps"
/"VARIABLE ATTRIBUTE VARIABLES= ", var1, " ATTRIBUTE=selectVars('yes')." .
exe.
dataset activate basedataset.
VARIABLE ATTRIBUTE VARIABLES=all ATTRIBUTE=selectVars('no').
insert file="yourpath\var1 selection.sps".
SPSSINC SELECT VARIABLES MACRONAME="!varlist" /ATTRVALUES NAME=selectVars VALUE = yes .
The list is now ready and can be called using the macro name !varlist in any command, for example:
freq !varlist.
or
SAVE OUTFILE ='Newdata.sav' /KEEP !varlist.

BIRT report parameter multiple selection value "All"

I have a problem with creating default value of 'All values' for a cascading parameter group last parameter. Actually I don't neccesary need that value to be default, but that would be preferable.
I have tried where I create additional data set with the needed value and additional data set with value All which uses different scripted data source, and another data set with computed column with full outer join, that column uses this code
if(row["userName"]==null ){
row["All"];
}else{
row["userName"];
}
and in the last cascaded parameter JDSuser which I need that All value I have added default value (All users).
In the data set with one value All in open I have script
ii=0;
in fetch
if( ii > 0 ){
return false;
}else{
row["All"] = "(All Users)";
ii++
return true;
}
and in the query data set, in beforeOpen script in if statement I have
if( params["JDSuser"].value!=null && params["JDSuser"].value[0] != "(All Users)" ){
This is used if I haven't selected All users value, and this works, though if I select All Users, it retrieves me no data.
I'm creating from this source example actuate link for example rptdesign download
If someone could give me some help, I would be very grateful.
The way you generate "(All values)" item in your selection list seems to me over complicated but if i understood correctly your case this part is working fine, the problem is not in the definition of the cascading parameter but the way it is used in the main dataset of the report.
Furthermore we have to assume we speak about the same query & beforeOpen script involved in this topic. No data are returned because if we don't do anything special when this item "All values" has been selected, then those filters are still active:
and role.name in ( 'sample grupa' )
and userbase.userName in ( 'sample' )
There are a couple of options to handle this. An elegant one is to declare a dataset parameter linked to your report parameter "JDSuser", and use a clause "OR" such:
and role.name in ( 'sample grupa' )
and (?='(All users)' OR userbase.userName in ( 'sample' ))
Notice this question mark, which represents a dataset parameter in your query. It is not intrusive: the beforeOpen script doesn't have to be changed. You probably need to do something similar with the other filter role.name, but you don't provide any information related to this. One more thing, in order to avoid bad surpises may be you should choose as value something more simple without brackets such "_allitems", and set "(All items)" as label.
Please refer to this topic for more informations about handling optional parameters. See a live example of optional parameters in a cascading group here.

Text input through SSRS parameter including a Field name

I have a SSRS "statement" type report that has general layout of text boxes and tables. For the main text box I want to let the user supply the value as a parameter so the text can be customized, i.e.
Parameters!MainText.Value = "Dear Mr.Doe, Here is your statement."
then I can set the text box value to be the value of the parameter:
=Parameters!MainText.Value
However, I need to be able to allow the incoming parameter value to include a dataset field, like so:
Parameters!MainText.Value = "Dear Mr.Doe, Here is your [Fields!RunDate.Value] statement"
so that my report output would look like:
"Dear Mr.Doe, Here is your November statement."
I know that you can define it to do this in the text box by supplying the static text and the field request, but I need SSRS to recognize that inside the parameter string there is a field request that needs to be escaped and bound.
Does anyone have any ideas for this? I am using SSRS 2008R2
Have you tried concatenating?
Parameters!MainText.Value = "Dear Mr.Doe, Here is your" & [Fields!RunDate.Value] & "statement"
There are a few dramatically different approaches. To know which is best for you will require more information:
Embedded code in the report. Probably the quickest to
implement would be embedded code in the report that returned the
parameter, but called String.Replace() appropriately to substitute
in dynamic values. You'll need to establish some code for the user for which strings will be replaced. Embedded code will get you access to many objects in the report. For example:
Public Function TestGlobals(ByVal s As String) As String
Return Report.Globals.ExecutionTime.ToString
End Function
will return the execution time. Other methods of accessing parameters for the report are shown here.
1.5 If this function is getting very large, look at using a custom assembly. Then you can have a better authoring experience with Visual Studio
Modify the XML. Depending on where you use
this, you could directly modify the .rdl/.rdlc XML.
Consider other tools, such as ReportBuilder. IF you need to give the user
more flexibility over report authoring, there are many tools built
specifically for this purpose, such as SSRS's Report Builder.
Here's another approach: Display the parameter string with the dataset value already filled in.
To do so: create a parameter named RunDate for example and set Default value to "get values from a query" and select the first dataset and value field (RunDate). Now the parameter will hold the RunDate field and you can use it elsewhere. Make this parameter hidden or internal and set the correct data type. e.g. Date/Time so you can format its value later.
Now create the second parameter which will hold the default text you want:
Parameters!MainText.Value = "Dear Mr.Doe, Here is your [Parameters!RunDate.Value] statement"
Not sure if this syntax works but you get the idea. You can also do formatting here e.g. only the month of a Datetime:
="Dear Mr.Doe, Here is your " & Format(Parameters!RunDate.Value, "MMMM") & " statement"
This approach uses only built-in methods and avoids the need for a parser so the user doesn't have to learn the syntax for it.
There is of course one drawback: the user has complete control over the parameter contents and can supply a value that doesn't match the report content - but that is also the case with the String Replace method.
And just for the sake of completeness there's also the simplistic option: append multiple parameters: create 2 parameters named MainTextBeforeRunDate and MainTextAfterRunDate.
The Textbox value expression becomes:
=Parameters!MainTextBeforeRunDate.Value & Fields!RunDate.Value & Parameters!MainTextAfterRunDate.Value.
This should explain itself. The simplest solution is often the best, but in this case I have my doubts. At least this makes sure your RunDate ends up in the final report text.