Reporting Services - translating labels into different languages - reporting-services

I'm finishing up my reports in my SQL Server 2008 Reporting Services project, and as one of the last steps, I need to make things translateable.
Since I have a bunch of reports, and they all share some identical labels, I decided to put all those labels I need to show into a SQL Server table, and I am surfacing that contents as a DataSet dsReportLabels in my reports.
This DataSet basically contains two fields: LabelName is the name of the label (e.g. "Count of items"), and Caption contains the text in the chosen language to be shown on the report.
But now here comes my mental block: how do I assign the dsReportLabels.Caption value to a e.g. textbox, based on the dsReportLabels.LabelName ?
So I need something like (pseudo-LINQ statement):
Textbox1.Value = from dsReportLabels
where LabelName = "some value"
select Caption;
but how do I express that in a Reporting Services code snippet?
I know how to reference things like Parameters!MyParameterName.Value and so on - but that doesn't really work here when I'm trying to extract a value from one column of the DataSet, given the value of the other column in that DataSet.
I bet this is totally easy to do in the end.... just can't seem to wrap my head around this right now.... anyone out there know how to do this?

This MSDN blog post describes one way of doing it. Essentially:
Create a lookup table with the LabelID, Language, and Caption.
Create a Stored Proc that gets all of the labelIDs and captions for a specified language.
Store the results of the SP in a dataset.
Store the dataset in a multi-value parameter.
Use the multi-value parameter in a custom lookup function.
So, the expression in your label textbox would call the custom function with the labelID, which would get the appropriate caption for the appropriate language.
Report Server 2008 also has a built-in Lookup function that may allow you to skip steps 4 and 5. If this is the case, your expression would call the built-in lookup function, which would go directly to the dataset. I don't have RS 2008, so I can't test this.

Related

MS Access 2013 Using Expression Builder to only display the first 25 characters in a text field for a report

I use the MS Access 2013 Expression Builder regularly.
But one thing I've never managed is simply to show only the first (say 25) characters of of a text field on the report.
It would seem to be a no-brainer. I've done far more complex things in Expression Builder without an issue. But shortening a text field on a report always return #Type! no matter how I try to adjust the expression.
It would seem to me that all I need is:
=Left([CompanyName],25)
But it just doesn't work! The report shows a #Type! error.
I can do this no problem by creating a RecordSet SQL string and setting the report RecordSource to it (with OpenArgs). But I can't manage it in Expression Builder.
What am I doing wrong?
When you build expressions for a form, then ANY column that exists in the datasource can be used - EVEN if not placed on the form.
However, reports have a significant difference. Your expressions ONLY work against data bound controls. In other words, the control has to be on the report (no doubt in this case in the details section of the report.
What this means is you have to drop into the details section (and you can and should use in design mode - add existing fields:
So, you need to add the Company name field to the report.
Of course you don't want it to display, so you can delete the label part, and set the control visible part = false. Eg: this:
Remember, you can't have the control reference its self.
In your case, the control you dropped "most" likely is called CompanyName, and then you changing the datasource expression to its self!!!
The other way?
well, you need to RE-NAME your control!!!
If you JUST drop the control onto the report, then its name will be CompanyName.
But, you NOW using =left(CompanyName,25) which POINTS to its self!!!!
So, as noted, you can drop in a company name control and then set visible = false.
The other way, is to CHANGE the name of the control to be DIFFERENT then the company name.
So, you can use add fields, but then in the other tab, rename.
So, say I just dropped in a Description column, but want to use left(10) on it
So, we do this:
Note VERY careful how I re-named the control.
I can't use left(Description,10), since that would refer to the VERY SAME control that I am attempting to use the expression against!!!
I would be saying, please use left of a control called description, but that description s the expression I am wanting to execute against!!!!
So, re-name the control. And now I can do this:
Note the arrow in above - note VERY careful how the control name is DIFFERENT then the data expression (Description) in this example.
Note VERY careful, I can now place OTHER controls on the report, and reference now:
I can reference Description in the expression, OR I CAN USE DescripitonLEFT in that expression!!!!
As you can see, we need a way to distinguish which control we are referencing here. In fact, some developers i have known as a habit NEVER use the same name for their controls vs the datasource of the control for this reason.
In your case the very same expression, and very same control BOTH have the same name - and thus you can't evaluate the expression of a left(Descripiton,10) against the VERY same control with the VERY same name!!!
So, you have to dis-ambiguate the name and the expression you want. In this case CompanyName. As noted, your left("some control") is the VERY same name as your current control.
Try just re-name of the control you dropped into the report.

SSRS error - A scope is required for all aggregates Used outside of a data

I'm getting SSRS error - A scope is required for all aggregates Used outside of a data region unless the report contains exactly one data set.
I searched on google but still not figure out
= iif(((100/(DATEDIFF(MIN([initiative_Start_plan]),"InitiativeDatasettansiq"),
MAX([initiative_end_plan]),DAY))),"InitiativeDatasettansiq")
*DATEDIFF(TODAY(),MIN([initiative_start_plan]),DAY)/100*-1)>1,1,
(100/(DATEDIFF(MIN([initiative_start_plan]),"InitiativeDatasettansiq"),
MAX([initiative_end_plan]),DAY)))
*DATEDIFF(TODAY(),MIN([initiative_start_plan]),DAY)/100*-1),
"InitiativeDatasettansiq")
Your field references look incorrect. they should be something like
MIN(Fields!initiative_Start_plan.Value)
or
MIN(Fields!initiative_Start_plan.Value, "myDataSetOrGroupName")
The error is basically saying that you are using an expression outside of a data region and therefore you need to tell it where to get the data for each field from.
If this does not help then you'll need to show more info. You will need to show where your expression is going to be used so please show your report design including the names of datasets and/or row/column groups (if any).

I have 3 parameters and I keep getting the forward dependencies are not valid error

The report parameter 'ServicePriorityNameParameter' has a DefaultValue
or a ValidValue that depends on the report parameter
"ServicePriorityNameParameter". Forward dependencies are not valid.
This is the error I keep receiving when trying to use this parameter.
I also have a WorkCategoryParameter which I specified the values for. Also a RequestNumberParameter in which a request number can be typed into.
I have tried reordering my parameters and also adding a separate dataset in which to run each parameter off of. I'm pretty new to SSRS so any words of advice will help. Thanks!
Reordering the parameters in the designer does not actually reorder them. If you open the report's rdl file (if using visual studio just right-click the report in the solution explorer and select View Code). In there, look for the ReportParameters section and reorder the parameters from there. Basically you need to make sure that any parameters that are dependent on other parameters are listed after the thing they are dependant on.
E.g. If you had a parameter called #Countries to list countries based on continent and the dataset that supplied the values to that parameter read something like SELECT * FROM dbo.MyCountryTable WHERE Continent = #continent then the #continent parameter would have to appear first in the list as #Countries depends on it.

SSRS Comma-delimited list as Parameter value

I have a report in SSRS. My parameter allows multiple values. My query has in the WHERE statement:
WHERE AllDiag IN (#Diag)
My user should be allowed to enter something like Z34.83,R30.0,0000.
These are 3 different codes to search for, so technically it is looking for:
WHERE AllDiag IN ('Z34.83','R30.0','0000')
I've tried all kinds of things like making the parameter properties in the query properties an expression using =join(Parameters!Diag.Value,"','"), and even entering the list of codes with the quotes already, but nothing seems to allow this to work.
I even tried some split function to see if it searched for each separately but I'm not sure I even use it right since there seems there might be some function that should run before.
I'm out of ideas. Any help is greatly appreciated!
I'm assuming your dataset uses the WHERE clause as you stated
WHERE AllDiag IN (#Diag)
I'm also assuming that you cannot easily produce a list of available parameter values to choose from.
So to create a parameter that allows the user to manually enter a list of values simply set 'Allow multiple values' on #Diag parameter. The user then simply types each value and presses enter after each one.
Note there is no need for comma's just type them one by one pressing enter after each.
When SSRS sees a multi-value parameter being passed to a SQL statement using an IN clause, it converts this to dynamic SQL automatically including adding the comma's. If you trace the report using the SQL Profiler, you can see the SQL that is generated.
I thought I would share this with you all in case you may have had issues (like I did) with passing multiple values in a single parameter from your web page to a SSRS report.
NOTE: This is different from passing multiple parameters, each with its own value into a report. The later, there are plenty of examples on the web.
This is very usefull when you need to basically pass into your report's SQL command a list of values for your report's SQL command to use using a "special" function, and where you do not know the number of times the values may be required, as the user can choose anything from one value to 'n' values (but we will hit a limit, as I'll explain later). It's also useful for generating Excel row-by-row extracts from your website - say for Pivot table handling or charting later on.
Unfortunately using IN() on its own tricks a lot of people and they cannot figure out why it does not work. That's because if you define your report in SSRS to expect a parameter straight into the IN() function, the system literally places the value as a parameter in the function and tries to compare what is essentialy a parameter "data type" with your column's data type and you will get errors.
If your report has SQL similar to this ...
SELECT t.Col1, t.Col2, etc
FROM myTable t
WHERE t.myColumn IN (#myListOfValues)
where #myListOfValues is something like "'value1','value2','value3',..." it "may" work but I found passing such a string from ASP.net into SSRS did not work and there are technical issues with string handling from the ASP.net side plus a limit depending your system and browser.
To get around possible issues, create a function in your SQL Server database to receive a string of values delimited by a comma and allow the function to turn your list into a table. That way the table can easily be linked using SQL and passed as a sort of "parameter feeder" into your report's SQL or dataset.
So without babbling on too much lets start with code and an example:
Firstly lets create a special utility function that converts a list of values into a table, and by the way this function can be used within your projects to do exactly that - split strings delimited by something into a table for anything else.
Open SQL Server and create a new function using your normal right-click NEW function command. Something like this ...
CREATE FUNCTION [dbo].[fnMakeTableFromList](#List VARCHAR(MAX),#Delimiter VARCHAR(255))
RETURNS TABLE
AS
RETURN (SELECT Item = CONVERT(VARCHAR, Item)
FROM (SELECT Item = x.i.value('(./text())[1]', 'varchar(max)') FROM (SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(#List, #Delimiter,'</i><i>')+ '</i>').query('.')) AS a
CROSS APPLY [XML].nodes('i') AS x(i)) AS y
WHERE Item IS NOT NULL);
NOTE: the delimiter does not have to be a single character! Again useful for delimiting using keywords, etc.
Note the XML logic and conversion in the function? That is because ASP.Net is going to literally pass some HTML into SQL Server and we're going to use it to strip off the data we need into a table.
Run the function with some values to test:
SELECT * FROM dbo.fnMakeTableFromList ('a,b,c,d', ',');
You should see 4 rows of data returned ...
a
b
c
d
That is the results in a table.
Now use this function in your SQL Reporting Services report:
Here is my report as an example:
SELECT DISTINCT s.StudentID
FROM tblStudents s
LEFT OUTER JOIN dbo.fnMakeTableFromList(#StudentList,',') AS list ON list.Item = s.StudentID
WHERE (#StudentList IS NULL
OR #StudentList='')
AND (l.Item IS NULL
OR l.Item = s.StudentID)
Note my example also caters for reporting every student ID if there was no value passed at all. So report every student found in tblStudents or report those based on the list of student IDs given, delimited by a comma. When you run this directly in SSRS, you'll be asked for a parameter #StudentList. In there type what ever values you need separated by a comma, and you should only get those student IDs. If not, make sure the report works "stand alone" first before going over to the ASP side.
Once you are happy your report works, and the function in SQL Server works, then we are ready to code the ASP.net side of things:
In your ASPX code behind page (C#) we need to control what the list is and how to pass it over to SSRS. Because we are dealing with a LIST<> here, I am only going to illustrate the way to do using a LIST<> to mimic an array. As you know C# does not have array terminology like you have with VB.
So in your ASP.net page paste this code in your PageLoad event ...
protected void Page_Load(object sender, EventArgs e)
{
//get parameters from the URL list
string strStudentList = Request.QueryString["StudentList"];
//create a List of parameters and pass it over to the report
List<ReportParameter> paramList = new List<ReportParameter>();
paramList.Add(new ReportParameter("StudentList", strStudentList));
//run the report
ReportViewer1.ServerReport.SetParameters(paramList);
}
Of course some objects in here have to be defined in your ASPx page.
For example I use a master page and as you can see, I did all of this to create a mailing list for printing on special sticky label paper.
<%# Page Language="C#" MasterPageFile="~/rptsStudentAdministration/StudentAdminReports.master" AutoEventWireup="true" CodeFile="rptStudentLabels.aspx.cs" Inherits="rptsStudentAdministration_rptStudentLabels" Title="Student Mailing Labels" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<rsweb:reportviewer id="ReportViewer1" runat="server" font-names="Verdana" font-size="8pt"
height="800px" processingmode="Remote" width="900px">
<ServerReport ReportServerUrl="<%$ AppSettings:ReportServerURL %>" ReportPath="/rptsStudentAdministration/rptStudentLabels"></ServerReport>
</rsweb:reportviewer>
</asp:Content>
Make sure you are using these as well in your .cs file:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Microsoft.Reporting.WebForms;
And that's it folks!
CONCLUSION:
If you need to generate a report in SQL Server Reporting services that relies on users selecting none, one or many values to control the logic in the report, then think of passing them all as a single parameter and using a function to turn your values into a table for ease of SQL management. Once you have the SQL working, you should be able to generate the report easily in design mode and using the above ASPx logic, be able to pass all the values delimited by a comma into into your report. An added bonus is to HIDE the parameter in SSRS and that way the user does not have to see what values they chose, and you control the entire report being generated programmatically.
There are a lot of answers here which don't really point to the solution.
Problem: the #Parameter value is passed to SQL as a comma delimited NVARCHAR value, NOT a list of data values you can JOIN to or use WHERE clauses with. When passed to SQL Server via a procedure call the data type of your parameters is also lost.
Solution in SQL Server 2016+ is to use the build in "split_string" function which returns a list of values from a single delimited field.
DECLARE #Parameter nvarchar(max);
Select *
FROM [dbo].[MyTable] a
JOIN (Select [value] FROM string_split(#Parameter)) b
ON a.ID=b.Value
It may be necessary to CAST your value field depending on the data type you are expecting SSRS to pass through. For example DATE values may look like this:
DECLARE #Parameter nvarchar(max);
Select *
FROM [dbo].[MyTable] a
JOIN (Select CAST([value] as DATE) as [value] FROM string_split(#Parameter)) b
ON a.SomeDateValue=b.Value
In Sql Server 2014 or lower, you can use custom functions to separate delimited list into table rows. Many examples exists on MSDN and StackOverflow, here's very detailed blog post detailing the pros and cons of many methods.
Either method would work with Command Text and Stored Procedure data sets.
I second the answer from Canadean_AS that you should setup a multi-select parameter.
However, if for some reason you have a hard requirement to accept a single comma delimited string into #Diag, you can try the following in your query:
WHERE CHARINDEX(','+AllDiag+',' , ','+#Diag+',') > 0
Be aware that you may encounter performance issues if your where clause is filtering a large dataset with this function.
A more efficient option is to parse #Diag into a table of its own and join that table to the dataset in the FROM clause.

Is there a solution for localizing "parameters/prompt" in SSRS 2008 R2 or 2012?

I'm using now SQL Server 2008 R2.
My website shows the report exactly as it is, including the container where the parameters appear (the client prefers it that way).
However, my website solution includes localization (Portuguese, English, Spanish).
I've tried to translate the parameters by creating one parameter for each language, and then show them according the selected one. It didn't work in SSRS 2008. Because I don't know how to find the visibility properties of prompt.
Does anyone know a solution... Or if SQL Server 2012 has solutions for translating parameter's prompt, or conditional visibility?
Thanks.
The only solution I've found so far (SSRS 2008, 2008R2, 2010, 2012) is to break the DRY commandments, and duplicate the reports with language codes as part of the report name (e.g. MyReport_sp.rdl, MyReport_de.rdl, etc) and then place a web service between the client request and the SSRS instance. The web service then has to field the request to the correct report based on a "Culture" parameter passed with the client's request.
This is NOT a good solution, though at least the Culture param is used in localizing the rest of the report as well. We still have hopes that at some future date MS will add prompt localizability and we can rename the report to MyReport.rdl and just have everything actually localized. Hmm, what a concept...
Another workaround would be to just put a number in the prompt for the parameter then prefix the label of each parameter with the localised version by either using "get values from query" or by using the expression builder with a switch statement in the label expression.
For the get values from query option you would have a dataset something like this if you have the translated versions in the query:
SELECT ParamLabel, ParamValue
FROM MyLocalisedParameters
WHERE UserLanguage = #Language
Or like this if not:
SELECT
CASE #Language
WHEN 'pt-PT' THEN 'Selecione Departamento: ' + ParamLabel
WHEN 'es-ES' THEN 'Seleccionar Departamento: ' + ParamLabel
ELSE 'Select Department: ' + ParamLabel
END AS ParamLabel
, ParamValue
FROM MyParametersTable
in both cases creating and assigning the Globals!Language to a Parameter called #Language.
Or if using the expression builder for a hardcoded set of values it would look something like this:
either way the end result would look something like this:
Not perfect but functioning and easier to maintain than several copies of the same report.
If you want it to look a bit tidier then just have the Parameter prompt as only one entry in the parameters list and set it to the default value to avoid repetition on every line.
There is none...
As per connect.microsoft.com, this feature has been requested after SSRS 2005 has been released, and while it is on Microsoft's TODO list, the programmer time to do this has never been allocated, and hence in 2012, SSRS is still not capable of doing that.
Although it's (with much effort) possible to translate everything else, it's not possible to translate the parameter prompt.
There is NO conditional visibility either, visibility of parameters is fixed.
Also, there is no way having SSRS use a supplied language instead of the one set in the browser language settings.
The only thing that you CAN do is write a C# program that loads your XML file, get's the report's parameter name(s) (and possibly the report's name as well), looks them up in a database, and automagically creates N reports for n languages.
Then, you have to redirect your users to the report in their language.
You then only need to write an upload tool, because you won't want to do that by hand.
The other way is to use the ReportViewer control, and re-implement parameter selection.
I think there's CrissCross that tries to do that, but it failed in all but 2 of the reports that I tested.
An evil hack would be:
parametername: babla_language1 / blabla_language2 / blabla_language3 / blabla_language4
and then use jQuery to get that string. do string.split('/')[index_of_language]
and then prey that / is never within "blabla_languageXY"
Edit:
I actually did that. You have to use setInterval to do it, because there is no way to detect change when you select a parameter.