I have searched and searched and have not been able to find the answer to this. I'm no stranger to SSRS, .Net (c# and vb.net), SQL, etc...been in it for years. I currently have a multi-select report parameter that is populated by a dataset in my report. There are hundreds of entries, so I built it to be driven by a wildcard character in a preceding parameter. Everything works fine right now. My question is this: is it possible to enter a wildcard value, select one (or more) of the filtered values and then store that/those value(s) on selection so that a user can go back and enter another wildcard value and select from a newly filtered list? (Basically, remember what has been selected in the overall dataset before report execution and create some sort of comma-separated list as the final parameter value to be passed to the report) I realize this may be better served in a web app w/a reportviewer control, but I'm trying to avoid deviating from the native SSRS server if possible. Thanks in advance!
The way I might approach this (not actually done it but the theory sounds ok)
Have 2 parameters for user input, your current one and a hidden one called say #filter (visible) and #filterHistory (this is the hidden one)
Have a textbox (formatted like button) with something like "Refine" as the text. Set the action to call your report again but set the #filterHistory to be something like #filterHistory & ", " & #filter. Basically we keep appending the last user input to the history.
Then your report would filter based on both parameters. You'll have to do some parsing of the delimited parameter now to split it out into the constituent parts but you get the idea.
I've no time to build a test report but hopefully that will point you in the right direction. If it doesn't help or work then comment and I'll see if I can knock up a quick example.
Related
TL;DR In a SSRS 2008 report which uses a custom assembly to do some extra calculations can I pass an entire report dataset as a method parameter?
Full story
I have an SSRS report with 3 datasets, each returned from an SQL query.
(In case it makes a difference to my question they're currently shared datasets although I'm sure local would work too)
The largest and primary dataset is a list of tasks which may or may not have been completed. I have information in here such as the ID, status, create date/time, target resolution hours etc of each task.
This dataset is displayed in a tablix and is the focus of the report.
The remaining two datasets are not displayed and are for reference. One is a simple one column query which returns a list of holiday dates for the UK. The other is a small table which contains our exact business hours.
At the moment I'm able to loop through the rows in the tablix of tasks and pass multiple values from the current row to a method. This is useful if I want to do some calculations based on data found only in the current row. For example I could take the create date/time and the response target hours and the assembly would return a target date/time for the current task. Cool so far.
I want to do a more complicated version of this where I not only pass in the row data but the 2 other datasets to get my return value. This is because in reality the due date calculation is much more complex and must take into account changing business hours and holidays from the other 2 datasets.
Can I pass a dataset as a method parameter to an assembly? Something like:
=Code.MyClass.MyMethod(val1, val2, dataset1, dataset2);.
I've been unable to find much definitive information on this. Nearly all tutorials demonstrate what I'm already doing by processing single rows. I'm sure I had an MSDN article that hinted this was not possible but I've lost it (helpful I know). There's a post on the Microsoft forums where a moderator says it's not possible. The general lack of information and tutorials suggests it's not possible or I'm doing this in the wrong way.
Any suggestions?
(I have alternate solutions such as having the assembly fetch the other datasets or just writing something outside SSRS but I'm not pursuing those until I knnow whether it can be done this way).
An older topic on the MSDN forums Iterate through rows of dataset in report's custom code offers a more definitive answer as well as a potential solution to this problem.
Passing the DataSet as an object or collection is not a possibility because:
A dataset in Reporting Services is not the same type of object as an ADO.Net dataset. A report dataset is an internal object managed by the SSRS runtime (it's actually derived from a DataReader object) and not an XML structure containing datatables, etc. and cannot be passed into the report's custom code.
The only way to effectively loop through the rows of a report dataset is to call a custom function or referenced method in a report data region expression. Using this technique, it may be possible to pass all of the the row and field information into a code structure, array or collection.
The hint given in the above statement suggests passing row and field information into a code structure. A contributor to the linked MSDN topic, Migeul Catalao developed a workaround using such an approach.
A real-world scenario of it's usage with example code demonstrating Migeul Catalao's solution can be found here.
Granted, it is still more of a row-by-row approach, so I would strongly suggest moving outside of SSRS and pursue alternative solutions.
Although I've accepted the other answer due to it being clear and helpful I didn't use that solution in the end (I was too stupid to understand it) and went for something else that works.
Disclaimer: This is a horrible hack. It works absolutely great in my scenario so I though I'd share in case it was useful to somebody else. There are many pitfalls here which could most likely be worked around given time.
I ended up following the advice in the comment given by Steven White and looking into LookupSet. This function allows you to query a dataset to return matching rows and a single column of data.
It looks like this:
LookupSet(Fields!ComparisonField.Value, // The value to search for, e.g '001'.
Fields!MatchField.Value, // The column to match on in the target dataset.
Fields!MyColumn.Value, // The column that will be returned.
"MyDataSet") // The dataset to search.
This returns a string array representing the returned values.
So far so good, but I needed ALL columns and rows. This is where the dirty hack appears in the form of string concatenation:
LookupSet(0, // Dummy ID 0.
0, // Matches the dummy ID 0 so all rows are returned.
Fields!Column1.Value + "[^]" // I concatenate all of the values into
+ Fields!Column2.Value + "[^]" // one string with the separator [^]
+ Fields!.Column3.Value, // so I can split them later.
"MyDataSet") // The dataset to query
I can now pass this to my custom assembly:
=MyAssemblyNamespace.Class.Method(LookupSet(0,0,Fields!Column1.Value..., "MyDataSet"), other, parameters, here)
Now in my C# method I have a generic object which after some reflection is actually an array of strings.
Cast to something useful:
var stringList = ((IEnumerable)MyDataSetObject).Cast<string>().ToList();
Split it:
foreach (var item in stringList)
{
var columns = item.Split(new[] { "[^]" }, StringSplitOptions.None);
// columns is a string[] which holds each column value for the current row
// So columns[0] is the value for column 1 in this row
// In my case I pushed the values to a DataTable row each time and built a datatable
// which when finished represented my dataset in full with all rows and columns.
}
I hope this makes sense to anyone trying to achieve a similar result.
I've got a report with a table looking like this:
UserCode|RecordID|OriginatingBranch|OriginatingAccount|HomingBranch|HomingAccount|Amount|ActionDate|SeqNo|Onus|Homedback
The last two columns are booleans, they contain either Y or N. In fact, the Onus column will only contain Ys. I need to have a subtotal at the end of each page showing how many Onus transactions there are and their value, and the same for Onus transactions.
I've tried several things including everything described here but when I try that I'm left with a nondescript #Error in my report. I have no errors or logs or anything, just an #Error where I should have a number.
Now I'm trying the answer from here, which says:
Add additional column and enter this expression: =Runningvalue(Fields!YourValue.Value,Sum,"yourtable1"), and set its hidden property to true.
In the page header or footer, use the expression: =Last(ReportItems!textbox12.Value) to get the subtotal of all previous pages.( assume that the above column’s detail row is textbox12)
I've put this in my table, this is my expression:
=RunningValue(IIF(Fields!HomedBack.Value="Y", Fields!Amount2.Value, 0),Sum,"Items")
//my tablix is called "Items" and my "Amount" field is a formatted string,
//the actual value is kept in "Amount2"
And lo and behold, I am getting the famous #Error again. My first row contains 0, and every row after that contains #Error.
I should note that I'm not viewing the report in a browser or interactively or anything like that, I'm using my company's old reporting library that is terrible and needs to be rewritten (I wish), and pretty much it takes a dataset and an RDLC and spits it out into a PDF.
Is there anything glaringly obvious that is wrong with my expression? I'm pretty new to RDLC so I feel like I'm missing something silly. Also is there any way to show exactly what these #Errors actually mean or correspond to?
Another note, I designed my RDLC in VS2013 if that makes any difference.
SSRS can give #Error because of data type mismatch. It might be evaluating Amount2 as string field instead of numeric. To avoid such conditions do the explicit conversion.
Try this:
=RunningValue(IIF(Fields!HomedBack.Value="Y", Fields!Amount2.Value*1.0, 0.0),Sum,"Items")
OR
=RunningValue(IIF(Fields!HomedBack.Value="Y", CDBL(Fields!Amount2.Value), 0.0),Sum,"Items")
OR
=RunningValue(IIF(Fields!HomedBack.Value="Y", CDEC(Fields!Amount2.Value), 0),Sum,"Items")
I really need your expert help :). Expanding on what I have learnt from querying data sets using adapters and filling a Grid View. I need some help on the following task.
I have a SQL Server Database which I am querying using C#. I already have solid working solutions of by a date range, a specific value. However, the business user would like to search by a list of values they provide as input into a form.
Similar to the below:
adapter.SelectCommand.Parameters.AddWithValue("#mindate", textBox1.Text);
The input will be taken from a text box or similar form based element. There should be no defined limit to the number of values e.g. I don't want to prevent the user from inputting 100 values for example.
By way of example.
User input: doc1.num1.value;doc2.num1.value;doc3.num1.value etc
Note: The document number field may contain a full stop. However, each value will be terminated by a ';'
In the above example, we would run the following query: select employee_id, docNumbers from tableName where docNumbers in (inputlist)
And the output would be:
Record 1: 1, doc1.num1.value
Record 2: 2, doc2.num1.value
Record 3: 3, doc3.num1.value
Thanks in advance guys and gals.
I guess what you are looking for is using an IN clause when doing your query.
I'm working with the MyMediaLite's item recommendation tool and I'm trying to understand how can I do in order to generate a prediction file which consists only of test set's items.
Actually with the default options (--overlap-items) it generates a prediction file which contains both items that are present in the test set and someone which aren't present in it. This is really annoying simply because I need to obtain correct recommendation in order to generate the metrics for my recommender (I use an external tool in order to generate the metrics).
So I've tried the option "--in-test-items" which should use as candidate items only those present in the test set, but this is not the result that I obtain. Actually I'm working with the movielens 100k dataset which I've binarized following a specific strategy: I've assigned 1 to items which have as rating 4 or 5, otherwise 0.
I want to report here the command that I use in order to produce the recommendation in a implicit feedback situation(supposing that I'm trying to execute the test on the first split of the dataset):
item_recommendation --training-file=u1.base --test-file=u1.test --prediction-file=u1.mml_res --in-test-items --recommender=ItemKNN --predict-items-number=10
There is something incorrect in this command? Do I have to fix something?
Thank you in advance.
Alessandro Suglia
The question was answered in this e-mail thread: https://groups.google.com/forum/#!topic/mymedialite/Sm6RXehqrYE
I stucked at a condition , where i need to share values between the pages. I want to share value from Codebehind via little or no javascript. I already have a question here on SO , but using JS. Still did'nt got any result so another approach i am asking.
So I want to know can i pass any .net object in query string. SO that i can unbox it on other end conveniently.
Update
Or is there any JavaScript approach, by passing it to windows modal dialog. or something like that.
What I am doing
What i was doing is that on my parent page load. I am extracting the properties from my class that has values fetched from db. and put it in a Session["mySession"]. Some thing like this.
Session["mySession"] = myClass.myStatus which is List<int>;
Now on one my event that checkbox click event from client side, i am opening a popup. and on its page load, extracting the list and filling the checkbox list on the child page.
Now from here user can modify its selection and close this page. Close is done via a button called save , on which i am iterating through the checked items and again sending it in Session["mySession"].
But the problem is here , when ever i again click on radio button to view the updated values , it displays the previous one. That is , If my total count of list is 3 from the db, and after modification it is 1. After reopening it still displays 3 instead of 1.
Yes, you could but you would have to serialize that value so that it could be encoded as a string. I think a much better approach would be to put the object in session rather than on the URL.
I would so something like this.
var stringNumbers = intNumbers.Select(i => i.ToString()).ToArray();
var qsValue = string.Join(",", stringNumbers);
Request.Redirect("Page.aspx?numbers=" + sqValue);
Keep in mind that if there are too many numbers the query string is not the best option. Also remember that anyone can see the query string so if this data needs to be secure do not use the query string. Keep in mind the suggestions of other posters.
Note
If you are using .NET 4 you can simplify the above code:
var qsValue = string.Join(",", intNumbers);
Make the object serializable and store it in an out-of-process session.
All pages on your web application will then be able to access the object.
you could serialize it and make it printable but you shouldn't
really, you shouldn't
The specification does not dictate a minimum or maximum URL length, but implementation varies by browser and version. For example, Internet Explorer does not support URLs that have more than 2083 characters.[6][7] There is no limit on the number of parameters in a URL; only the raw (as opposed to URL encoded) character length of the URL matters. Web servers may also impose limits on the length of the query string, depending on how the URL and query string is stored. If the URL is too long, the web server fails with the 414 Request-URI Too Long HTTP status code.
I would probably use a cookie to store the object.