I have googled it a lot and found that usually it cannot be done. I came across one of the hacks here:
http://www.bp-msbi.com/2011/04/ssrs-cascading-parameters-refresh-solved/
But its not working for me in ssrs 2005. Just wondering if anyone else tried it in 2005.
Or is there any other hacks that can be tried.
As per this article the dependent parameter gets refreshed only when its values are invalidated by the selection in the first parameter. If we can invalidate the dependent parameter every time a parameter changes we will enforce a complete refresh. An easy way to do this is to attach a value such as a GUID obtained with the NEWID() T-SQL function.
So basically we want to introduce a fake parameter in between two real parameters. This fake parameter is supposed to return new values everytime as the storedproc behind it will add a guid to the resultset everytime that proc is called. So it forces complete refresh of the other parameters.
Now the main issue I am facing is :
Setting the default value of this fake parameter.
For the available values the storedproc behind the fake param runs and it returns data in the format say : result1,result2_GUIDFROMSQL
Now it looks like the same storedproc is called again to set the defult value if i ask it to get the default value from query. But as the storedproc is run again new guid comes and so the old value cannot be found so its not being set as desired.
I just need to figure out a mechanism to pass this guid from introduced param to the next param.
Thats where I am failing.
My issue can simply be replicated by creating a param whose datasource is this querystring.
select getdate() id, #name nid
So in this case how to set a default value for this param.
Below I'm going to present a detailed scenario and then I'll show the example implementation based on Visser and Abbi's answers.
Imagine that I have a report where each row is a project. A project has a Status column with values "In Progress" or "Complete" and a Project Manager column whose values are a person's name. Here are the rows in the table:
Project A (Status = In Progress, Project Manager = Bob)
Project B (Status = In Progress, Project Manager = Tom)
Project C (Status = Complete, Project Manager = Jack)
Project D (Status = Complete, Project Manager = Tom)
Project E (Status = Complete, Project Manager = Jill)
I want to have 2 parameters on my report
Show Completed Projects? - This is a boolean parameter
When false will only show "In Progress" projects A & B
When true will show "In Progress" projects A & B in addition to "Complete" projects C, D, & E.
Project Manager - This is a multi-value text parameter whose options and default values will need to change based on the Show Completed Projects? parameter upon which it is dependent.
If Show Completed Projects? is set to false then only "Bob" and "Tom" options will show up because they are the project managers for the in progress projects Project A & B respectively.
If Show Completed Projects? is set to true then in addition to "Bob" and "Tom" you will also have "Jack" and "Jill" show up as options because they are project managers for the inactive projects Project C & Project E respectively.
Now for the implementation:
Show Completed Projects? parameter
Project Managers dataset query (See Visser and Abbi's answers for details on how this generates a key that will change based on the independent parameter and will force SSRS to reload the default values)
SELECT
[ProjectManager_Key] =
pOuterAlias.[ProjectManager_Key] + '_' +
CAST(ROW_NUMBER() OVER(ORDER BY pOuterAlias.[ProjectManager_Key] DESC) AS NVARCHAR(MAX)),
[ProjectManager] = pOuterAlias.[ProjectManager]
FROM
(
SELECT
[ProjectManager_Key] =
pInnerAlias.ProjectManager + '_' +
CAST(ROW_NUMBER() OVER(ORDER BY pInnerAlias.ProjectManager ASC) AS NVARCHAR(MAX)),
[ProjectManager] = pInnerAlias.ProjectManager
FROM
(
SELECT
[ProjectManager]
FROM
[dbo].[Project]
WHERE
Status = 'In Progress' OR
#ShowCompletedProjects = 1
) pInnerAlias
) pOuterAlias
ORDER BY
pOuterAlias.[ProjectManager]
Project Manager parameter
General
Available Values
Default Values
Projects dataset
Query
SELECT
*
FROM
[dbo].[Project]
WHERE
(
Status = 'In Progress' OR
#ShowCompletedProjects = 1
) AND
Project Manager IN (#ProjectManager)
Parameters (Make sure to note the [#ProjectManager.Label] portion which will make it match the project on the actual project manager value from the database and not the key that we generated.
Finally I was able to resolve this. This link was a helpful start.
http://www.optimusbi.com/2012/07/16/multilevel-cascading-select/
Basically what it does is : Writing parameter query in a manner so that the dependent parameter changes its value every time you change its parent parameter.
The query adds rownumber with a "_" preceeding it. So every time user selects other values the rownumber changes and hence the query resultset.
Then when using the resultset remove the text after the underscore to get the real codes.
There is a workaround to fix this issue for all situations.
Note that the previous answer provided, writing parameter the query in a manner so that the dependent parameter changes its value every time you change its parent parameter, works for some cases but not all cases. If the dependent parameter's "Available" values change as a result of another parameter AND the dependent parameter is visible, it works, If the dependent parameter is hidden or internal, or if the "Available" values do not change as a result of the other parameter, it will not work.
The foolproof workaround is to define a custom function in the report and call it in an expression for the dependent parameter. The custom function takes the parameter's (the parameter that the dependent parameter depends upon) value as an argument, and simply returns its value. Even though function is simply taking the value and returning it, SSRS does not inspect the code and assumes that the code could do anything (generate a random number, pull files from disk, etc ...). So SSRS calls the function every single time the value changes regardless of whether the dependent parameter's "Available" values change, and regardless of whether the dependent parameter is visible, hidden, or internal.
Something like this:
public function returnArg(ByVal TheArg As String) As String
return TheArg
end function
Assume you have two parameters:
Parameter1
Parameter2
And that Parameter2 depends upon Parameter1.
Set Parameter2's value as an expression that includes the call to Parameter1 with the function, like:
=CODE.returnArg(Parameters!Parameter1.Value)
Now in this case Parameter2 simply displays the value in Parameter1, but this logic can be extended to more complex expressions and more than one parameter. As long as there is a CODE.returnArg(...) function call for each parameter in the expression, SSRS will always refresh the value.
#Abbi's second link is no longer valid. The article can now be found at:
http://www.optimusinfo.com/multilevel-cascading-select/
Unfortunately the images are broken and the article is a little incomplete without them. There is one image I was able to locate in its moved location (I could not find the others even with trying appropriate variations): http://www.optimusinfo.com/wp-content/uploads/2012/07/Multilevel-Cascading-with-Select-All-18.jpeg
This gave me the last clue I needed to get the technique working: when you're setting up the dataset parameter properties, you need to manually specify the parameter value as e.g. [#City.Label] rather than the usual plain old [#City] (which corresponds to [#City.Value].
This is because the technique alters the "Value" to a custom value which can no longer be looked up in the DB! So you need to use the user-friendly, db-existing "Label" as the parameter. (Probably should be obvious but...) The rest is all pretty standard if you understand report builder.
Also note that this link as it stands doesn't work with multi value cascading parameters. However it can easily be modified to do so: just alter the parameter stored procs to join to a value splitting function. I adapted mine from the udf_splitvarible function given at SQL Server - In clause with a declared variable
The modification is fairly simple but I'll give an example. This is from the article (with terrible formatting fixed).
SELECT
l11.CompanyName1+'_'+ CAST(row_number() over( order by l11.CompanyName1 desc) AS VARCHAR(50) )as CompanyName11
,l11.CompanyName
FROM
(
SELECT
l1.CompanyName+'_'+ CAST(row_number() over( order by l1.CompanyName asc) AS VARCHAR(50) )as CompanyName1
,l1.CompanyName
FROM
(
SELECT DISTINCT CompanyName
FROM Customers
WHERE City IN(#City)
)l1
)l11
ORDER BY l11.CompanyName ASC
Change:
SELECT DISTINCT CompanyName
FROM Customers
WHERE City IN(#City)
to:
SELECT DISTINCT CompanyName
FROM Customers
INNER JOIN udf_SplitVariable(#City,',') v ON City = v.Value
This all applies to SQL Server 2008/Report Builder 3 also.
I wasn't able to understand/apply #borkmark's answer. The limitations don't seem to apply to my case.
Related
I am not sure if this is possible in Report Builder or not. I want to put a text box in a Report Builder report and then search the database for a specific person and display that in a subreport. Is this possible and, if so, how would you suggest I do it? I have tried researching it online without success.
This part will produce a parameter into which your user can type whatever they want
You need to set up your report to use parameters. You can set these parameters up to require user input either from manual entry or by picking from a pre-defined list.
Assuming you are returning your data using a SQL query, you can then reference these parameters in your dataset script. If for example you had a parameter called FirstName and another called Surname, and you only wanted to return values in your data set that matched both exactly, you would reference these parameters like so:
select PersonID
,FirstName
,Surname
,OtherDetails
from PersonTable
where FirstName = #FirstName
and Surname = #Surname
If you would rather have more of a 'search' type function, you can use the SQL like operator and wildcards, though bear in mind this will have a potentially very detrimental effect on your query performance:
select PersonID
,FirstName
,Surname
,OtherDetails
from PersonTable
where FirstName like '%'+#FirstName+'%'
and Surname like '%'+#Surname+'%'
This part shows you how to change that parameter so it provides a drop down menu. This part is optional.
If you want to provide a list of available options to select from, you can create a parameter that has a list of 'Available Values'. These can either be manually typed in by yourself - hard coding them in to the report design - or you can make them data driven by basing the parameter on a second dataset.
To get that list of people, you would want to return the ID of the person you are looking for as well as the details that are end-user friendly to be visible in the report:
-- select distinct so we have no duplicates
select distinct PersonID as Value -- Value is what is used to the query. This ideally will be a uniquye identifier
,FirstName
+ ' '
+ Surname as Label -- Label is what the user sees. This can be a bit more verbose and detailed
from PersonTable
order by Surname -- Specify how you want the options ordered
,FirstName
If you set this dataset as the source by selecting Get Values From A Query in the parameter options, you will see the drop down list appear when you run the report. Users can then select one, click Run Report and have their selection impact the data that is returned.
I have a report that I am working on that will do the following:
Return results based first on the community selected by the user.
Filter to find alike addresses within the community, based on the number of square feet at each address.
Set the end date (a column within the data table) to a user defined parameter for use in a WHERE at the end of the query.
The relevant information is stored in the following places:
Community: ub_subdivision.descr
Address: ub_serv_loc_addr.location_addr
SqFt: arp_ops.dbo.vw_ub_serv_loc_classifications.SqFt
I have setup the query with 3 parameters:
#Community
#Months
#Address
When the user is running the report, the following should happen (in this order):
The community parameter should populate the values stored in ub_subdivision.descr and allow the user to select the community they want from that list.
The address parameter should populate the values within the selected community from step 1, and allow the user to select the address they want from that list.
Based on the selected address, the query should store the value of the SqFt related to this address and use that in the WHERE statement as follows: WHERE (arp_ops.dbo.vw_ub_serv_loc_classifications.SqFt = #Address)
The months parameter should allow for user input to define how many months of data they want. This parameter is called in the query in the WHERE statement: WHERE (ub_bill_run.def_end_dt > DATEADD(m, -#Months, GETDATE())).
If I save the dataset and create a "table report" in Report Builder 3.0 it does the job of recognizing the various parameters and loading them into the Parameters folder and into the Datasets' parameters.
The problem I have is that I am not able to change the parameter properties to display Available Values and select "get from a query". If I go this route, and try to run the query I get an error that I am using "forward dependencies".
I need the #Address parameter to display the address field as the label, but store the sqft field as the value. This is the way I know how to do this and, unfortunately, it doesn't seem to work.
I would appreciate any insight anyone may have.
Thanks!
John
There is one way to solve this make sure the order should be in the order of
#Community
#Months
#Address
change order to:
#Community
#Address
#Months
just delete existing #month and again add it manually and save it.
i hope it will work for you.
You cannot have parameters based on your main data set.
The forward dependency error is caused because your data set is to be filtered by your parameter, yet it is depending on the same data set to find its' set of values. This is a sort of paradox.
When using queries to define the set of values for your parameters, make sure you create a new data set for each parameter.
Next, make sure the parameters are listed in the order you want them to run. Within the data sets for your parameters, you may use where clauses to make them dependent on one another in the order that they run.
In this example:
Parameter data set for Community:
SELECT DISTINCT ub_subdivision.descr
FROM [YOUR JOINED TABLES]
Parameter data set for addresses:
SELECT DISTINCT ub_serv_loc_addr.location_addr
FROM [YOUR JOINED TABLES]
WHERE ub_subdivision.descr IN (#Community)
Parameter data set for SqFt:
SELECT DISTINCT SqFt
FROM [YOUR JOINED TABLES]
WHERE ub_subdivision.descr IN (#Community)
AND ub_serv_loc_addr.location_addr IN (#Address)
You should also make a month data set for your #month parameter, however it is not dependent on the other parameters so I will leave that to you.
Hope this helps!
I have run into a couple situations where I have a single report, but the user requires two ways to run it. For example, they want to either enter an employee id and pull up a single employee record, or they want to enter the company and department, or multiple companies and departments, and return employee records for all selected departments & comapnies.
I know how to do the cascading parameter thing, so I can do either way, but I dont want to have 2 reports, I would like to have one report with optional parameters. I envision two tabs or check boxes or soemthing when they first open the report, that say, "Click to view single record" and "Click to view multiple records" then which ever one they choose, they can enter the parameter(s) and run.
I have been researching and I am leaning towards sub reports and/or using ISNULL in the parameters and marking them as 'allow null'. STill playing with it, but if someone has a link to a nifty tutorial, I would be much obliged. Thanks.
What you can still squeeze comfortably out of SSRS:
A multi-value company parameter based on a dataset;
A cascaded (from company) multi-value department parameter based on its own dataset;
An optional multi-value employee id parameter, based on a dataset that might filter on company/department;
An optional custom employee id parameter, plain INT input;
Your datasets would be something as follows.
For #Company:
SELECT CompanyId, -- Param value
CompanyName -- Param display in SSRS
FROM vw_AllCompanies
And for #Department:
SELECT DepartmentId, -- Param value
DepartmentName, -- Param display in SSRS
FROM vw_AllDepartments
WHERE CompanyId = #CompanyId
And for #EmployeeId:
SELECT EmployeeId,
FullName
FROM vw_Employees
WHERE (DepartmentId = #DepartmentId AND CompanyId = #CompanyId)
OR (#DepartmentId IS NULL AND CompanyId = #CompanyId) -- Optional
Then your main dataset would do:
SELECT * -- Okay, don't use "*", but select actual columns :)
FROM vw_AllMyData
WHERE EmployeeId IN (#EmployeeId) -- The cascaded param
OR EmployeeId = #SomeCustomEmployeeId -- The custom INT input param
In my experience, this is slightly clunky, but probably the best you can get out of basic SSRS. If you want more flexibility I recommend you built something in your app around it, and pass the ID as a final parameter to the report.
I have a report which displays a table full of raw data.
Prior to entering this report, the parent report asks you to select a 'Service' & 'Department'
Depending on which Service/Department you select from the parent report, this RAW data will be filtered to show the relating data.
Straight forward enough, and it works, great.
I have a new requirement now.
If the chosen Service is equal to 'Service X' I need the data to be filtered again on that Service, department, but also to add aditional filter, on their 'team'.
so that the data will also be filtered where the team matches the user running the report's team.
I have a dataset already created which returns the user running the reports 'team'
And also a new parameter called 'team' which defaults to the user running the reports AD number'
The new requirement is, if the Service = X, then filter the data on the department but also on THAT users 'team', if the Service is not equal to X, do nothing.
I think I need to alter the Filters section of the Tablix Properties but am not sure what I need to put in the Expression, Operator, Value
So far I have tried =IIf(Fields!Service.Value = "Service X", Fields!Team.Value, nothing) in the Expression, set the Operator to In and tried filtering on the 'team' from my new dataset which stores the current users 'team' but it is not working.
Does anyone have any suggestions?
For these sorts of conditional filters I've had best results with using the IIf statement (or whatever) to return a string and filtering based on that, e.g. something like:
=IIf(Parameters!Service.Value <> "Service X" or Parameters!Team.Value = Fields!Team.Value
, "Include"
, "Exclude")
Then you can set the Operator to = and the filter value to Include. Just seems to a bit more robust in my experience.
Reading over this, you could even set the IIf statement up as a Calculated Column in the dataset and filter on that.
I have to set the start_date of my report depending of a report parameter. The time stamps are calculated in a database query.
My expression looks like this:
=SWITCH (
Parameters!report_type.Value = 1,First(Fields!daily_start.Value, "Timestamps")
,Parameters!report_type.Value = 2,First(Fields!weekly_start.Value, "Timestamps")
,Parameters!report_type.Value = 3,First(Fields!monthly_start.Value, "Timestamps")
)
Unfortunately I get the error message:
A value expression used for the report parameter 'time_from' refers to a field. Fields cannot be used in report parameter expression
I know, that this is not allowed because SSRS cannot be sure in which order datasets are called. But I think this is not dangerous.
All time stamps are received by query without parameter. The parameter report_type is selected by a user before the report will be generated.
Can someone give me a hint for a workaround?
Here's the workaround - get the value using SQL.
Create a new Dataset called StartDates:
SELECT CASE
WHEN #report_type = 1 THEN daily_start
WHEN #report_type = 2 THEN weekly_start
WHEN #report_type = 3 THEN monthly_start
END AS StartDate
FROM MyTable
You already have the #report_type and #time_from parameters. With the #time_from parameter, set its Default Values to Get values from a query using the StartDates dataset and the Value field StartDate.
Now, you'd think this might be enough to make it work - you're referencing this query as the default value and as you change the #report_type parameter the other parameters refresh, but the first date in the #time_from parameter never changes. That's because the refresh happens on the Available Values query, not on the Default Values query.
So you also need to wire up the Available Values query to the StartDates query. Now your query will fire on the change of #report_type and the default value will be set to the appropriate date for your selection.
I switched from a query to Stored Procedure and was getting this error. Things I tried:
Ensured I had sufficient permission on the database (you need EXEC rights or DBO to run teh sproc)
Delete the existing parameters (and then use refresh fields to refresh/get the correctly named ones back)
Remove the square brackets around the stored procedure if you've specified that
Sometimes, Expressions can get a bit verbose. I have created a Report Code Function and then used that as the Parameter Value.
For example, I created a Code function called "CalculateDateSet" and then set the Report Parameter to this expression:
"=Code.CalculateDateSet(Parameters!Month.Value, Parameters!Year.Value"