Optional Multi-Value parameter in BIRT - birt

I have a BIRT report that have 4 optional parameters.
startdate; enddate; stringparam and listparam (multi-value parameter).
I followed "bluish" code on this link How do I set a parameter to a list of values in a BIRT report?
and it works if I give either one or all of the value to the parameter. However, when I leave the parameter blank, I got a blank report (which is incorrect result).
This is my query:
select f1,f2,f3,f4
where f1 >= ? -- startdate parameter
or f2 <= ? -- endate paramter
or f4 = ? -- stringparam
and ( f3 in (''/*?listparam*/) )
I did query on my Oracle db to see what parameter is being passed to my query I got 'NULL' as the VALUE_STRING when I leave the parameters values as blank.
Any help is appreciated.

It sounds like you want to occasionally search for records on one to three of the 4 criteria in the parameters.
There are couple ways to do this:
One way is to use like, and set the default parameter value to % which is the wild card. when the parameter runs it returns all values. Be aware this can be problematic if the fields contain null.
or f4 like ?
So you would need to use something similar to below to return null values.
or (f4 is null
or f4 like ?)
I usually prefer to use "All" as my default parameter value, as you can see in the second "and" we look to see if the parameter value is All, if it is all values for PRODUCTTYPEM1.CATEGORY are returned, if it is anything else it looks for the entered valued in the field PRODUCTTYPEM1.CATEGORY.
where PRODUCTTYPEM1.ACTIVE = 't'
and DEVICE2M1.ISTATUS = 'In Use'
and ( 'All' = ?
or PRODUCTTYPEM1.CATEGORY = ?)
For this to work you will need two parameter entries, the first is for All, the second is for any values other then All.
I only have one Category parameter in the report, the second entry looks at the same parameter a second time if the parameter value is not All
The way this works. (expanded explanation by request)
Opening where statement, and simple second criteria for 'In Use'
where PRODUCTTYPEM1.ACTIVE = 't'
and DEVICE2M1.ISTATUS = 'In Use'
The third criteria is two parts set in parenthesis with an OR statement dividing the two parts
and ( 'All' = ?
or PRODUCTTYPEM1.CATEGORY = ?)
If the value of the parameter is All, then the first part of the statement is met, and the query skips everything thing else in the parenthesis. It is like not have the parameter in your SQL query at all.
If the value of the parameter is NOT all, the first part of the statement is not met so the query looks for the parameter value in field PRODUCTTYPEM1.CATEGORY.
Your final query will probably look something like this, though it is problematic in that we have a Default date of 'All', you probably want to use some kind of date for your default value like Jan 1, 1900.
select f1,f2,f3,f4
where f3 in (''/*?listparam*/)
AND ( 'All' = ?
OR f1 >= ?) -- startdate parameter
AND ( 'All' = ?
OR f2 <= ?) -- endate paramter
AND ( 'All' = ?
OR f4 = ?) -- stringparam

Related

DAX - CONCATENATEX TO FILTER AN UNRELATED TABLE

I have an unrelated table ('Selected Values Slicer') that is then used as a slicer to select values. I need to use these selected values to filter another table ('Results Table').
Doesn't seem to be working as I'd expect it to. The output shows a 0 when more then 1 item is selected but works ok when 1 value is selected
VAR __SelectedValues =
CONCATENATEX(
ALLSELECTED('Selected Values Slicer'[Description]),
'Selected Values Slicer'[Description],
",")
RETURN
CALCULATE(
[TotalCount],
'Results Table'[Description] IN {__SelectedValues}
)
__SelectedValues RETURNS "Selected Value 1,Selected Value 2"
What I'm expecting is __SelectedValues to RETURN "Selected Value 1","Selected Value 2"
The following syntax will return "Selected Value 1","Selected Value 2" as you asks
CONCATENATEX(
ALLSELECTED('Selected Values Slicer'[Description])
,"""" & 'Selected Values Slicer'[Description] & """"
,","
)
Regarding filtering. I was trying to use the string as filter, but I didn't manage it the way you want. I can't say what is the reason for DAX not to do that, but asked Marco Russo about the case. So, I'll add the answer since a get it (upd. the answer added to the end of the answer).
To filter the table with a string of CONCATENAX() you can try the following sytax ( I checked it with a dummy data):
VAR __SelectedValues =
CONCATENATEX(
ALLSELECTED('Selected Values Slicer'[Description])
,'Selected Values Slicer'[Description]
,","
)
RETURN
CALCULATE(
[TotalCount]
,FILTER(
'Results Table'
,CONTAINSSTRING(
__SelectedValues
,'Results Table'[Description]
)
)
)
Regarding result you want to achieve. A below code, I believe, is enough. You have a slicer and you want to apply its values to the result. I have a feeling, you don't need to change a contex to the slicer and no context can influence it. If it's not like that, then the code should be altered, but the idea remains the same - get a column with a unique values and use it as a filter. I checked the syntax and it was functioning.
CALCULATE(
[TotalCount]
,'Results Table'[Description] IN VALUES('Selected Values Slicer'[Description])
)
P.S.
My first answer was not ok. I messed some info and gave an incorrect input. I'm sorry for that.
P.S.S. The answer from Marco Russo:
"IN looks for an exact match in a table (IN VALUE is a better choice for your need, and a better one is:
TREATAS ( VALUES ( slicer[column1] ), table[color] )
The result of CONCATENATEX is a string, so you should use CONTAINSSTRING - DAX Guide to do the search, but it would be slower and potentially inaccurate."
This is the answer from his colleague

How can I use a PSQL timestamp function as a parameter in Ruby?

I am using a Ruby method to access task information from a Postgres database.
def query(statement, *params)
#logger.info("#{statement}: #{params}")
#db.exec_params(statement, params)
end
def tasks_completed_for_date(date="CURRENT_DATE")
sql = <<~SQL
SELECT tasks.name AS task_name,
timetable.start_at AS start_at,
timetable.end_at AS end_at,
timetable.duration AS duration,
timetable.start_at::date AS task_date
FROM tasks
JOIN timetable ON tasks.id = timetable.task_id
WHERE timetable.start_at::date = $1
AND timetable.duration IS NOT NULL
ORDER BY tasks.name ASC;
SQL
result = query(sql, date)
if result.ntuples > 0
result.map do |tuple|
{
task_name: tuple['task_name'],
start_at: tuple['start_at'].slice(11, 5),
end_at: tuple['end_at'].slice(11, 5),
total_time: tuple['duration'].slice(0, 5),
task_date: tuple['task_date'].slice(5, 5)
}
end
end
end
I want the default value to of the query to be whatever the current date is. I thought the best way to do this was to set the default parameter in the method called tasks_completed_for_date to the string CURRENT_DATE. This string would be interpreted by PSQL as the method CURRENT_DATE and return data based on that date. Instead I receive the following error:
ERROR: date/time value "current" is no longer supported
I am not using 'current' at all and I know that whatever it is, it's obsolete. Is there a way to pass a PSQL method to the query (in place of $1) as I am trying here that doesn't result in an error?
Your problem is that the $1 placeholder's value will be the string 'CURRENT_DATE', not the literal value CURRENT_DATE. The result is that you're effectively saying 'CURRENT_DATE'::date and that doesn't work:
psql> select 'current_date'::date;
ERROR: date/time value "current" is no longer supported
LINE 1: select 'current_date'::date;
^
You need to either get the literal value current_date into the query or find a string that properly casts to a date. The easiest thing would be to use 'now' since that casts nicely:
psql> select 'now'::date;
date
------------
2019-10-22
(1 row)
A quick change to the method's date argument's default value should be good enough:
def tasks_completed_for_date(date = 'now')
You can replace $1 with one of these methods:
DATE 'today'
DATE 'now'
Also you can use:
TIMESTAMP 'today'
So for example call method as tasks_completed_for_date('today')

Conditional Select - Part 2

I have the following situation within a PL/SLQ function. Depending of existing table field value I might run a different select. Specifically: I can have multiple rows for a particular BILL CODE (PINGPONG) where I would only need to get the SYS_FIELD value. This field has to be fetched only once according to following condition: If fields prep_seq_num=0 and primary_ind=0 then just get this row sys_field value straightaway and do not take care of other possible prep_seq_num and primary_ind values different from 0. If that rows is not existing, fetch the sys_field value from prep_seq_num!=0 and primary_ind=1. For both case only one instance/row must be possible So in the first case I should run:
SELECT SYS_FIELD
INTO v_start_of_invoice
FROM BILL
WHERE TRACKING_ID = v_previous_trackingID
AND BSCO_CODE_ID = 'PINGPONG'
AND CHRG_ACCT_ID = v_ACCT_ID
AND PREP_SEQ_NUM = 0 -- maybe not needed here
AND ITEM_CAT_CODE_ID=1
AND PARTITION_KEY = v_prev_partition
AND SUBPARTITION_KEY = v_prev_subpartition
AND PRIMARY_IND=0;
In the second case
SELECT SYS_FIELD
INTO v_start_of_invoice
FROM BILL
WHERE TRACKING_ID = v_previous_trackingID
AND BILL_CODE_ID = 'PINGPONG'
AND ITEM_CAT_CODE_ID in ('5' , '-100')
AND PARTITION_KEY = v_prev_partition
AND SUBPARTITION_KEY = v_prev_subpartition
AND PRIMARY_IND=1;
Not sure I'm making it very complicated, but still I 'd need to know whether IF THEN ELSE or CASE or whatever should be used and how.
You can utilize an implicit cursor for loop.
for rec IN ( <your query that gives all records)
LOOP
--compare the value of this variable and decide in the IF condition.
IF rec.prep_seq_num=0 and rec.primary_ind=0
THEN
-- write the query to get the sys_field
ELSE
-- write alternative query.
END IF;
END LOOP;

data comparison oracle (source to target)

I have a query below from source this is how Active flag for target is derived
select case when active_end_date is null then 'Y' else 'N' end
from csi_item_instances cii
where instance_id = <<INSTALL BASE ID>> --- (MP.INSTALL_BASE_ID)
I am comparing the active field value using the SQL below, is there better way to do this?
select * from stgdba.Stg_s_csi_item_instances cii, MDHDBA.M_CUSTOMER_PRODUCT mp
where cii.instance_id= MP.INSTALL_BASE_ID
and cii.active_end_date is null
and MP.ACTIVE_FLAG = 'N'
If that value is to be permanently calculated like that, you could do that in a view / computed column, which would make the logic a bit more permanent and not repeated all over the place.
(Stylistically, I would also try using ANSI joins a bit more.)

set filter to - INLIST - Visual Foxpro 7

I am working on some legacy code, and I have the following wonderful issue. I am hoping some FoxPro experts can help!
The infrastructure of this legacy system is setup so that I have to use the built-in expression engine to return a result set, so no go on the SQL (i know that would be so much easier!)
Here is the issue.
I need to be able to do something like
PUBLIC ARRAY(20) ArrayOfValuesToFilterBy
SELECT dataTable
SET FILTER TO logicalField = .T. and otherField NOT INLIST(ArrayOfValuesToFilterBy)
However, I know this wont work, I just need the equivalency...not using SQL.
I can generate the list of values to filter by via SQL, just not the final record select due to the legacy infrastructure constraint.
Thanks!
First, a logical field you do not have to do explicit
set filter to Logicalfield = .t.
you can just do
set filter to LogicalField
or
set filter to NOT LogicalField
Next, on the array. VFP has a function ASCAN() which will scan an array for a value, if found, will return the row number within the array that matches what you are looking for.
As for arrays... ex:
DIMENSION MyArray[3]
MyArray[1] = "test1"
MyArray[2] = "something"
MyArray[3] = "anything else"
? ASCAN( MyArray, "else" ) && this will return 0
? ASCAN( MyArray, "anything else" ) && this will return 3
If you are doing a "set filter", the array needs to be "in scope" for the duration of the filter. If you set filter in a procedure the array exists, leave the procedure and the array is gone, you're done.
So, you could do
set filter to LogicalField and ASCAN( YourArray, StringColumnFromTable ) > 0
Now, if you want a subset to WORK WITH, you can do a SQL-Select and pull the data into a CURSOR (temporary read-write table) that has the same capabilities of the original table (except auto-increment when adding)...
I typically name my temporary cursors prefixed with "C_" for "CURSOR OF" so when I'm working with tables, I know if its production data, or just available for temp purposes for quicker display, presentation, extractions from other origins as needed.
use in select( "C_FinalRecords" )
select * from YourTable ;
where LogicalField ;
and ASCAN( YourArray, StringColumnFromTable ) > 0;
into cursor C_FinalRecords READWRITE
Then, you can just use that...
select C_FinalRecords
scan
do something with the record, or values of it...
endscan
or.. bind to a grid in a form, etc...
The INLIST() function takes an expression to search for and up to 24 expressions of the same data type to search.
SELECT dataTable
SET FILTER TO logicalField = .T. AND NOT INLIST(otherField, 'Value1', 'Value2', 'Value3', 'Value4')
I am making some assumptions here, that what you want to do is create a filter with a dynamic in list statement ? If this is correct have a play with this example :-
lcList1="ABCD"
lcList2="EFGH"
lcList3="IJKL"
lcList4="MNOP"
lcList5="QRST"
lcFullList=""
lcFullList=lcFullList+"'"+lcList1+"',"
lcFullList=lcFullList+"'"+lcList2+"',"
lcFullList=lcFullList+"'"+lcList3+"',"
lcFullList=lcFullList+"'"+lcList4+"',"
lcFullList=lcFullList+"'"+lcList5+"'"
lcField="PCode"
lcFilter="SET FILTER TO INLIST ("+lcField+","+lcFullList+")"
The results of the above would create the following filter statement and store it in lcFilter
SET FILTER TO INLIST (PCode,'ABCD','EFGH','IJKL','MNOP','QRST')
you can then use macro substitution
Select dataTable
&lcFilter
Bear in mind that there is likely to be some limitations on how many items you can define in a INLIST() statement

Resources