I'm trying to check our compliance with standards for documenting patient information, using SSRS 2008 R2. For example, in the group header for PatientID, I have =Not IsNothing(Fields!DATEOFBIRTH.Value). Now, I'd like to count the number of patients for which that returns True. The obvious way is
=Sum(Iif(Not IsNothing(Fields!DATEOFBIRTH.Value)
, 1
, 0
)
)
(which actually doesn't work, because I have multiple lines per patient, but never mind that for the moment.) The problem is that if I find my logic was wrong, I have to make the correction in two places, and it won't be obvious if I forget. In Crystal, I'd either use a running tally, evaluating on the change of group, or a manual tally with WhilePrintingRecords;, having a formula returning the T/F result in both locations. What's the generally-accepted SSRS way to do this? Thanks.
If you want to centralize logic, you can either use custom code in a report or create a custom assembly. With custom code, you'd have to update every report that uses that same logic if you find you need to make change, but it's simple to add to a report. With a custom assembly, you have to create a class library, compile it and add the code to your machine so BIDS can use it (and to every developer's machine if applicable) and to the report server. The advantage with the custom assembly is that there is one place to store the logic (not counting the distribution of the DLL) so every report gets updated automatically when you update the logic. This link is a starting point for you and provides links to more details on both of these options: http://msdn.microsoft.com/en-us/library/ms155798(v=sql.100).aspx.
Related
I have a dataset that includes details of who is providing certain services. I've been asked to provide a report that splits out how many cases each provider is working on (and the assets involved). So far so good, I've got a report that is grouped by provider and sums the assets and counts the number of cases.
Now I've been asked to add in how many cases they are working as an advisor on. The cases where they are advisor will not be cases that they are working on, so I'm a little stumped on how to pull that information into the table.
All I need to do is add something like:
=sum(iif(Fields!Advisor.value = Fields!Provider.value,1,0),"DataSet1")
but the issue is that I need the Fields!Advisor to be looking at the whole dataset, and the Fields!Provider to use the current provider within the group.
I tried using ReportItems!Textbox.value to refer to the cell that contains the name of the provider, as follows:
=sum(iif(Fields!Advisor.value = ReportItems!Textbox10.value,1,0),"DataSet1")
but it gives an error that I can't use an aggregate function over a ReportItem. I don't want to use the aggregate function over the report item - I want to treat it as a constant!
Any ideas?
Is there an issue with SPLIT(JOIN()) functions in SSRS 2012?
Here's why I ask...
I've just set up an SSRS 2012 server. I have an existing report I built in SSRS 2008 R2, which pulls from a 2005 database. I created a new project in MVS 2010 and added the existing rdl.
When I preview the report, the performance is at least 5 times worse than it is when I preview it in MVS 2008. I ran a trace and found that it took quite a while for SSRS to even execute the SP. Once it did, it rendered quickly.
I was trying to think of something that might slow down the SP's execution. The only thing I came up with is that I have a lot of multi-valued parameters I pass into the SP using SPLIT(JOIN()) functions. Have those been replaced by something new in 2012? If not, I don't even know where to start looking for the problem. My initial google searches have turned up nothing.
Has anyone experienced this problem or know of a list of things that worked well in 2008 but not so well in the new version?
I hope this question isn't too vague. Thanks for reading!
EDIT: I feel silly. I just traced the 2008 report execution and it turns out it does the same thing, which I never noticed before. The rendering is really quick after the SP shows up in Profiler. So...I have no clue what the problem could be. Any help would be GREATLY appreciated!
I would just stick with a predicate like:
Where thing in (#Sets)
Where the 'Sets' variable could be from another dataset I created obtained from SQL like:
Select 'Brett' as Name
Union
Select 'Anna'
Union
Select 'John'
Union
Select 'Jenny'
Simple choose to get the data for sets from 'get data from a dataset'. Once the variable is set SQL 2008R2 and higher should do the lifting for you with figuring out the clause of the predicate in expression of Where thing in (#Sets) actually translates to:
Where thing in ('Brett', 'Anna', 'John', 'Jenny')
The primary solution to speeding SSRS reports and decreasing server load is to cache the reports. If one does this (either my preloading the cache at 7:30 am for instance) or caches the reports on-hit, one will find massive gains in load speed.
Please note that I do this daily and professionally and am not simply waxing poetic on SSRS
Caching in SSRS
http://msdn.microsoft.com/en-us/library/ms155927.aspx
Pre-loading the Cache
http://msdn.microsoft.com/en-us/library/ms155876.aspx
If you do not like initial reports taking long and your data is static i.e. a daily general ledger or the like, meaning the data is relatively static over the day, you may increase the cache life-span.
Finally, you may also opt for business managers to instead receive these reports via email subscriptions, which will send them a point in time Excel report which they may find easier and more systematic.
You can also use parameters in SSRS to allow for easy parsing by the user and faster queries. In the query builder, type IN(#SSN) under the Filter column that you wish to parameterize, you will then find it created in the parameter folder just above data sources in the upper left of your BIDS GUI.
[If you do not see the data source section in SSRS, hit CTRL+ALT+D.
See a nearly identical question here: Performance Issuses with SSRS
Create a UDF which will take a comma (or some other delimiter you want to use) separated list, and return a table you can join on.
https://blogs.msdn.microsoft.com/amitjet/2009/12/11/convert-comma-separated-string-to-table-4-different-approaches/
Then you can take set up a parameter in your sproc such as #TheList varchar(max)
You should then be able to use it in a JOIN, Use it to create a temp table and then join on that in your query, or use it as a sub-select.
We use this quite often, and found that if you are primarily using values which are Integers, then the returned table should be a table of INT's to increase performance.
Pseudo example:
declare #TheList varchar(max)
set #TheList = ('1,2,3,4,5,6,7,8')
select *
from dbo.MyRecords r
join dbo.udf_CreateArrayTable(#TheList) at on r.RecID = at.RecID
I was told about pre-filtering when writing reports in CRM 2011 and it sounded like something I should add to my knowledge base so I Googled it and found:
MSDN
PowerObjects
and a whole bunch more. These gave me a good understanding of the how for both automatic and explicit. The one thing I missed though was why. I mean in general the articles said things like context specific or reduce the size of the query but I failed to translate that into the nuts and bolts business case example. For example one of the articles stated that it will greatly enhance your reports but what does that mean to the person in sales running the report.
In other words I could easily add CRMAF_ to my queries but how it makes sales reports better I couldn't explain. Note I used better as that is the word the author of one article used so I took that to mean extra capability not better performance...?
So a quick business case understanding would be great.
Thank You
JB
It's very easy to make an example.
You need to create a simple report to display a list of accounts created starting from a selected date.
You just do a SQL Query as
SELECT * FROM FilteredAccount WHERE createdon => #selected_date
You publish your report and everyone is happy.
One month later there is a new requirement and you need change the report because is necessary to filter also by country (or city, or a custom field)
Would you prefer to edit the report, adding parameters (and change the queries too) or enable pre-filtering and allow the user to apply some filters (based on fields that maybe will be added in the future) before your report runs?
I have created a complex report in Microsoft Business Intelligence.
The report has its own (fairly complex) WHERE clause. Is it possible for the user to set the CreatedOn date as part of the criteria?
UPDATE
I was looking at this again. On a basic report (one table) if i import the report over one created with the report wizard, this give you the filter options and works.
On the more complex report that uses the union statement to pull data out of two tables the filter options are available however they have no effect, this is after removing the where clause.
END UPDATE
Thanks
Luke
I have been doing some research into this topic, and it appears that if you alias the fields and prefix them with CRMAF_ this allows you to add filtering. I'm going to look at this over the next few days and see how it works. However it has been noted that several people have been unable to get this to work correctly.
Please note you need to prefix both the table and fields.
You then can set the filter.
I want to group by a report item, but that's not allowed.
So I tried creating a parameter...not allowed as well.
Tried referencing from footer...failed again.
This is somewhat complicated.
Let me explain:
I have textbox22, it's value is:
=Code.Calc_Factor(Fields!xx.Value, fields!yy.Value...)
This is embedded VB code in the report that's called for each row to calculate a standard factor.
Now to calculate the deviation from the standard factor, I use textbox89, whose value is:
=(Fields!FACTOR.Value - ReportItems!textbox22.Value)/ReportItems!textbox22.Value
Don't get confused between Fields!FACTOR.Value and textbox22.Value, they are different.
Fields!FACTOR.Value is the factor used, textbox22.Value is what it should be (standard factor).
Now I want to create a group which splits deviations into 2 groups, > 1% or not.
So I tried creating a group:
=IIF(ReportItems!textbox89.Value > 1,0,1)
...But then SSRS complains about using report items.
I have run into a similar problem of using report items in the past, but this is a new case!
Any help greatly appreciated.
Have you tried adding a calculated field to your dataset?
Here is how it works:
While you are in the layout view of the report, open "datasets" tool window(in my environment it is on the left).
Right click on the DataSet you are working with and add a field, you can use a calculated field, and build your formula appropriately
Then you should be able to group on this field
-Dan
I'm not 100% that someone won't have some magic solution for this but I have run across similar problems myself in the past. I believe (but could be wrong) the problem Reporting Services is having is that it only renders once and what you're asking it to do is render the data before rendering the grouping which it doesn't do.
The only way I have ever been able to produce the exact results I need is to make the data rendering happen exclusively in the SQL (through the use of table variables usually) and then use Reporting Services merely as a display platform. This will require that your factoring algorithm gets expressed in the T-SQL within the stored procedure you will likely have to write to get the data in shape. This would appear to be the only way to achieve your end result.
This has the bonus feature of separating report design and presentation from data manipulation.
Sorry I couldn't provide a SSRS solution, maybe someone else will know more.