Get unique values of parameter in Caml query - reporting-services

I am generating SSRS reports using SharePoint list and using below Caml query in my dataset.
<RSSharePointList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ListName>Test_FAMM</ListName>
<ViewFields>
<FieldRef Name="Region" />
</ViewFields>
</RSSharePointList>
However, I want to get only distinct values of the parameter.
Any modification?

Unfortunately, CAML doesn't allow use of DISTINCT. There are a couple of workarounds that you may be able to use.
See:
https://sharepoint.stackexchange.com/questions/77988/caml-query-on-sharepoint-list-without-duplicates
Or:
What is the best way to retrieve distinct / unique values using SPQuery?

Related

SSRS join(Parameters!ACCNUMBER.Value, ",") generate rendering error

i am building a SSRS report using report builder 3.0.
i have parameter ACCNUMBER which contain a large number or records, and i am using inside my report the below function :
join(Parameters!ACCNUMBER.Value, ",")
when i generate the report for and i selected few values from ACCNUMBER parameter the report is generated normally; however if i generate the report while Select All values in ACCNUMBER parameter, i receive the below error:
appreciate your assistance.
It looks like you are on the right track but just need to also update the value for MaxJsonDeserializerMembers.
There is a (c)onstraint (on .NET framework or Web server I think) that allows only 1,000 values to be loaded under parameter drop down boxes
Add the following tags under section. Note: If
doesn't exists in config files add the whole tag from
below just after <\system.web> section. If "appSettings" is already
there just add 2 keys from below. I put 30000 as maximum number of
items, but you can use any number of values.
<appSettings>
<add key="aspnet:MaxHttpCollectionKeys" value="30000" />
<add key="aspnet:MaxJsonDeserializerMembers" value="30000" />
</appSettings>
From Mladen's MS BI Blog

SSRS shows dropdown instead of date picker

I have a report with a single parameter Date/Time.
The available values are from query
select cast(getdate() as date) c1 union all
select cast((getdate() - 1) as date)
But both VS preview and SSRS 2017 show that parameter values in dropdown/combobox and no date picker is presented. I need a date picker.
Any idea what's wrong ?
I tried converting it to various date types but nothing works. It doesn't work in IE, Chrome, nothing.
This is the rdl code:
<DataSets>
<DataSet Name="ds">
<Query>
<DataSourceName>SSDB</DataSourceName>
<CommandText>
select cast(getdate() as date) c1 union all
select cast((getdate() - 1) as date)
</CommandText>
</Query>
<Fields>
<Field Name="c1">
<DataField>c1</DataField>
<rd:TypeName>System.DateTime</rd:TypeName>
</Field>
</Fields>
</DataSet>
</DataSets>
<ReportParameters>
<ReportParameter Name="Date">
<DataType>DateTime</DataType>
<Prompt>Date</Prompt>
<ValidValues>
<DataSetReference>
<DataSetName>ds</DataSetName>
<ValueField>c1</ValueField>
<LabelField>c1</LabelField>
</DataSetReference>
</ValidValues>
</ReportParameter>
</ReportParameters>
<Language>en-US</Language>
From my testing and what I've done personally in SSRS, the issue is with you specifying a specific set for available dates. The answer on this link describes what happens well.
Using a dataset to assign values to a filter, you must agree, is a typical practice of single-select and multi-select filters. By specifying values, you are telling SSRS some date values are legal, while others are illegal. The only way it can forbid illegal values be entered by the user is by taking away the anything-your-heart-desires-to-choose date picker.
Basically, the point is that you won't have an option for a date picker if you add anything to the available values. You can set a default value with no problem, but with no available values provided, you will see the date picker.

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.

in Primefaces datatable can I use "filter by" with two fields?

I want to use something like this:
filterBy="#{proyecto.clientes.id_cliente}, #{proyecto.clientes.descripcion}"
Is there a way to filter a column by two different fields in the same filterbox?
I have searched in documentation and in this web without finding nothing.
EDIT: Of course, both fields are rendered in the same column as this:
<h:outputText value="#{proyecto.clientes.id_cliente} - #{proyecto.clientes.descripcion}" />
Create one String variable on your Bean side(Or server side) and merge both the required Strings values in that variable.
Now you can access newly created variable at your view side and check for filtering.

How to Make a Condition Optional in FetchXML

I have some SQL reports that has very slow performance, so we converted all of them into FetchXML, but all the SQL reports has all the conditions optional, something like this:
SELECT
...
FROM ...
WHERE (#operator = 'All' OR Operator = #operator)
AND (#new_gen_comp_name = 'All' OR new_gen_comp_name = #new_gen_comp_name)
...
In the parameters values, there is a value All if the user select this value, the condition will be ignored and therefore it will get all the values from that field.
Now I want to do that in FetchXML, I tried to put two conditions with filter or between them, one for the value and another to include null values like this:
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true">
<entity name="incident">
...
...
<filter type="and">
<filter type="and">
<condition attribute="createdon" operator="on-or-after" value="#StartDate" />
<condition attribute="createdon" operator="on-or-before" value="#EndDate" />
</filter>
<filter type="or">
<condition attribute="new_gen_comp_type" operator="in" value="#new_gen_comp_type" />
<condition attribute="new_gen_comp_type" operator="null" />
</filter>
</filter>
...
...
</entity>
</fetch>
This worked fine only if the user select all the values for the parameter #new_gen_comp_type, but the problem is if the user select only specific values, it will include the null values too, and that is wrong.
So, is there any way to make these conditions optional in case if the user select select all for the values of the parameter like in SQL?
Since you're doing this in SSRS, you don't have an option to change the Fetch XML which is what you really need to do. (If the user selects "ALL", don't include a constraint on new_gen_comp_type)
The only option I can think of is kind of dumb but it should work. Create a new attribute on Incident new_all that is defaulted to "ALL", and run an update statement to populate all of your existing Incidents to "ALL". Then change your FetchXml filter to:
<filter type="or">
<condition attribute="new_gen_comp_type" operator="eq" value="#new_gen_comp_type" />
<condition attribute="new_all" operator="eq" value="#new_gen_comp_type" />
</filter>
If the user selects "ALL" the second statement will be true and everything will be returned. If the user selects something besides ALL, the second statement will always be false and the first statement will only return what matches.
Please note that attribute operator="in" will not work with multiple values. You need to make a value child tag with each value...
From the XSD:
The attribute "value" is used for all operators that compare to a
single value (for example, eq).
The element "value" is used for operators that compare to multiple values (for example, in).
Some operators require neither the attribute "value" or the element "value" (for example, null).
I found a solution for this using the dataset filters, I removed all the conditions from the fetchxml(I left only those conditions that aren't optional). Then I made all the parameters multi valued, if the user select more than one vale it will make the parameter optional, otherwise if he selects one value it will search with it.
I added a filter for each condition, for example if you have a condition in the fetch xml like this:
<condition attribute="attribute1" operator="in" value="#a1" />
...
...
Then I added a filter for each conditions like so:
Right click the data set that the table is reading from.
Click the properties.
Choose the filters tab.
Click the Add button.
In the expression choose the fild [attribute1].
For the operator choose in.
For the value, click the function button fx and enter the following expression =IIf(Parameters!a1.Count>1,Fields!attribute1.Value,Parameters!a1.Value).
So if the user selects only one value for the parameter values, the condition will be false then the field attribute1 will be compared to the parameters value, therefore the condition will be applied otherwise the field value will be compared to its value, which is always be true, so that the condition will be always true and ignored.
The problem with thi solution is that, the user can't select multi values and search with them, it will be treated as it selects all the values, I tried to overcome this by:
Checking if the selected values for the parameter values equal to the count of the total values of the dataset that the parameter is populated from or if it is not populated from a data set, compare the total values to the total count of all the values instead of checking if the count is greater than 1, but I couldn't be able to do that. I got an error that I couldn't use an aggregate in the filters expressions.
Trying to include a null value into the parameters values (I couldn't do that in my case because the parameter values was populated from a dataset), so that I can check if the selected value is null then ignore the condition, somthing like this: =IIf(Parameters!a1.value = nothing,Fields!attribute1.Value,Parameters!a1.Value).
If you could make one of these works, then this solution will work fine.
Note that, you might need to use Parameters!a1.Label instead of Parameters!a1.Value if that field has a label attribute1name and a value attribute1, this is the way fetchxml works. So use parameter label to get the name to compare it to attribute1name or use paramter value to compare it to attribute1.
Although an assumption, I see you are attempting a FetchXML based report in CRM.
It is suggested to use CRM default filters in this case.
The query requires no condition and just have select columns.
This would allow you to have optional parameters.
[Note: Filters/Parameters are applicable only of entity/related entities being queried]