SSRS custom code issue - reporting-services

I am working on a SSRS report which has a Table with 2 groups. Used custom code to store the outer group data and display it in the header. This works great for most of the data. However, found couple of instances where the last page of the group( A group can run into multiple pages and there is a page break at the start of each group) is displaying the data of the next group in the header. When I display the stored group data in the group footer, the group details are correct. Confused as to why the header is displaying incorrect data for a few groups. Any pointers as to why this is happening?
Custom code:
Public Shared Dim field as String
Public function Set field(ByVal Val as String)
field1 = Val
End Function
Expression in Outer group to save the group data:
=Code.Setfield(field name)
Expression to display the saved group data in Header:
=Code.field1
Thanks.

Resolved it by adding group variable and using PageName property.
Set the group variable as a concatenation of the group fields that I required. Set PageName to the group variable.
In the header use Globals!PageName to access the group data. Spilt the concatenated values using the split function.
Thanks!

Related

How do I combine data types in a SSRS Parameter?

Background -- I’m trying to create a report in SSRS using Report Builder 3.0 that contains multiple parameters. The request is when the report is opened, display all rows of data. The end user can then select one or more of the parameters to reduce the results displayed. I can get it to work using something like the following.
Data sets for Parameters where available values are from a query,(dataset type is text)
For fields that are numbers:
SELECT 0 'FACG' UNION ALL SELECT DISTINCT STR(ACG) FROM STG_CSI_SA_CONFIRM
For columns containing text:
SELECT 'Any' 'FunderName' Union All Select DISTINCT NAME FROM STG_CSI_SA_CONFIRM
In the dataset for the report I have this:
WHERE ('Any' IN (#FrName) or Fname.name in (#FrName)) AND ( 'Any' IN (#FACG) OR FLIST.FACG IN (#FACG))
The results are two Parameter boxes, one says 0, one says Any, and the report runs when first opened. End user can then select one or more numbers from FACG or one or more names from FRName.
My question is, how can I adjust the first parameter to show ‘Any’ instead of a zero as the default value? All the values returned would be integers of 7 digits long. When I simply change the 0 to Any I get an error message about converting data types. If I use STR() I can get a list out of SQL server I get a list as I expect. ( Any, 1234567, 1234568 etc.) But I cant get the list to work in SSRS.
Thanks
R
Two way to do this.
1. Make sure the dataset that provides values for your parameters has two columns, an ID column that you will use to actually do the filtering/joins in your dataset and the other column is the label which will be visible to the user. Something like
ID Label
'Any' 0
'1234567' 1234567
'1234568' 1234568
If you main data dataset is a query (not a Stored proc) then you can simply have a parameter dataset as above but without the 'Any' row. Then set you available value to the parameter dataset and the default values to the same parameter dataset. By default all parameters will then be selected.
In your main data dataset the query would be along the lines of
SELECT * FROM myTable WHERE myColumn IN (#myParameterName)
SSRS will turn the selected values from the parameter into a list of comma separated values and inject them into the query for you.

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.

SSRS - Using RunningValue vertically

I am running a report on SSRS where 2 of the columns are running value.
Before it was like:
SO i was running the report by each code at once.
I changed it to allow multiple codes to be shown in the report (Grouping by Code) and it gave me the below:
As you can see, its doing running value horizontally.
I want it to do it vertically by each code like below:
MAYBE USING THE COLUMN GROUP AS SCOPE WILL WORK? I AM NOT SURE HOW TO USE COLUMN GROUPS IN SCOPE. ANY IDEAS?
You can try this by writing custom code -
Go to Report Properties and write code
public corder as integer
Function GetcOrder(order as integer) as integer
corder =corder + order
Return corder
End Function
Give a Name to Order text box
Next write an expression to calculate cumulative order value by calling function written in first step
preview output
Repeat the same step for rest of cumulative values .. please make sure to define public variable like
public corder as integer
All the Best!
Got it working!
Using the column group as scope works. I was using Nothing before as the scope. THen tried using the group in square brackets until i realised it needs to be passed as a string like "groupName"

How to prepare recursive reports based on a field value?

I am preparing a SSRS report where a table in the body has to be generated by considering a field value in header part and should repeat the same for all values of that field. I have created a group in body and used the expression =First(Fields!Field.Value, "DataSet"). It is generating all the values in the table but value in the header part doesn't change.
I also tried creating a group in the table and using one of the value from the group in the header part. But it is not possible as we are restricted to use group variables inside the group but not in the header part of the report.

calling a query from a report textbox

I have a report based on a number of different queries. Most of the queries use the value of a row's customerID textbox as a key to extract specific data from other fields.
Here is what I have for the Control Source property of one of the textboxes:
=DLookUp([Level],[qryLevel],[Me].[customerID])
Here is the SQL for qryLevel:
SELECT TOP 1 Level, myDate FROM sometable WHERE custID=Me.customerID ORDER BY myDate DESC
qryLevel works when tested independently, but the DLookUp function does not seem to be working properly because Access gives a dialog box asking for each parameter and then outputs #NAME? in the textbox when no values are input into the dialog boxes.
How can I get each of these textboxes to output its own result from a separate query?
DLookup function arguments must all be strings: http://allenbrowne.com/casu-07.html
So for the first two arguments, just enclose them in double-quotes.
For the last argument, the documentation says it's equivalent to a SQL where clause, without the word 'where'. Actually since you're returning only a single record from your query you probably don't need the last argument at all:
=DLookup("[Level]", "[qryLevel]")
Although, I don't see how qryLevel can work as an independent query since it refers to Me which implies a container object. Better to express as:
SELECT TOP 1 Level, myDate
FROM sometable
WHERE custID = [Forms]![MyForm]![customerID]
ORDER BY myDate DESC
... which will work in any context--inside or outside a form.